Методы делегата в дочернем классе иногда не вызываются с помощью компилятора Swift 5
ОБНОВЛЕНИЕ: Как sunshinejr указал здесь, это было исправлено и будет выпущено вместе со следующей версией Xcode/Swift.
Я видел много странного поведения после обновления Xcode 10.1 до Xcode 10.2, как с базами кодов Swift 4 и Swift 5.
Одна из проблем заключается в том, что на одном ViewController методы делегата ScrollView больше не вызываются. Упрощенная иерархия представлений выглядит следующим образом:
| ScrollView (ParentScrollView)
| -- Stack View
| ---- ScrollView (ChildScrollView)
| ---- ScrollView (ChildScrollView)
| ---- ScrollView (ChildScrollView)
Он действует как представление с несколькими страницами: ParentScrollView
можно прокручивать по горизонтали, ChildScrollView
по вертикали.
ViewController является делегатом всех представлений Scrollview (устанавливается в раскадровке), но методы делегата (например, scrollViewDidEndDecelerating
) не вызываются при прокрутке любого из представлений (ParentScrollView или ChildScrollView). базовый класс из ViewController
соответствует UIScrollViewDelegate
.
Я попытался установить делегатов в коде, кроме того, что я понятия не имею, что я могу делать неправильно. Преобразование не изменило никакого кода в классе, но все работало хорошо перед обновлением. Я также не смог найти никаких изменений в жестах, делегатах или ScrollViews в целом в заметках о выпуске Swift 5.
Кажется, это ошибка компилятора Swift 5. Кроме того, иногда это работает, иногда нет - все без изменения какого-либо кода или настроек проекта.
Почему это больше не работает? Кто-нибудь еще испытывал подобное поведение?
Ответы
Ответ 1
ОБНОВЛЕНИЕ: Как sunshinejr указал здесь, это было исправлено и будет выпущено вместе со следующей версией Xcode/Swift.
Я нашел проблему, вот как ее воспроизвести.
class A: UIViewController, UIScrollViewDelegate {
// ...does not implement 'scrollViewDidEndDecelerating'
}
class B: A {
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
// Will not be called!
}
}
Что работает:
class A: UIViewController, UIScrollViewDelegate {
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
// Probably empty
}
}
class B: A {
override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
// Will be called!
}
}
Компилятор, похоже, считает, что метод делегата не реализован, если базовый класс его не реализовал. Если только дочерний класс реализует его, он не может его найти.
Я до сих пор не могу объяснить, почему это поведение изменилось в Swift 5, но, по крайней мере, я нашел решение. Может быть, кто-то может дать дальнейшие идеи?
Ответ 2
Мы столкнулись с этим с UITextViewDelegate
Другой обходной путь - добавить тег @objc
к методу в суперклассе.
Ответ 3
Похоже, что эта проблема существовала еще в 2016 году и была исправлена в один момент: https://bugs.swift.org/browse/SR-2919
Ответ 4
Как указал Ян, это регрессия Swift 5. Это отслеживается на Swift JIRA, а также на радаре (rdar://problem/49482328). Это также уже исправлено (PR здесь), но нам нужно дождаться следующего выпуска Xcode/Swift.
Редактировать: Начиная с Xcode 10.3, мы заметили, что ошибка исправлена, но мы все еще отслеживаем, исправлена ли она навсегда.
Ответ 5
Мы испытываем ту же проблему после обновления с 4.2 (Xcode 10.1) до 5.0 (Xcode 10.2). В нашем случае это UITableViewDelegate. Родительский класс реализует методы, связанные с прокруткой, в UITableViewDelegate, однако методы, связанные с табличным представлением для этого делегата (такие как DidSelect RowAtIndex), реализованы в дочернем классе. Методы в дочернем классе были вызваны без проблем, прежде чем мы обновили XCode 10.2 с помощью Swift 5.
Переопределение методов делегата в дочернем классе, предложенное Яном Шлорфом, решило проблему.
Ответ 6
Я столкнулся с той же проблемой только со схемой выпуска после обновления до Xcode 10.2. Я также протестировал Xcode 10.3, и это точно такое же поведение.
Для тех, кто не хочет добавлять @objc везде в вашей реализации делегата.
Быстрое решение - отключить оптимизацию компилятора Swift 5 в настройках сборки:
Для тех, кто уже обновился до Xcode 10.3, кажется, что этот параметр настроек сборки больше не виден, но вы все равно можете изменить его напрямую через файл pbxproj вашего проекта, и он должен появиться в пользовательском интерфейсе xcode позже.
SWIFT_COMPILATION_MODE = singlefile;
Ответ 7
Поскольку все методы UIScrollViewDelegate
являются опциональными, вы никогда не увидите ошибку от компилятора, если он считает, что вы их не реализовали, скорее всего, происходит то, что Apple изменила сигнатуру метода в Swift 5 (снова) и по какой-то причине инструмент миграции не работал
Проверьте имена методов вместе с UIScrollViewDelegate
обновленным до документации USwift 5, вы увидите, что, вероятно, ваши имена методов отличаются, просто исправьте их, и все должно работать снова.