Необязательный метод протокола Swift 3 ObjC в подклассе

У меня есть следующая иерархия классов:

class ScrollableViewController: UIViewController, UITableViewDelegate { // ... }

Это реализует один UITableViewDelegate метод протокола, например tableView:willDisplayCellAt:

В моем классе SpecificScrollableViewController, который наследует от ScrollableViewControllerновые дополнительные методы протокола больше не вызываются, например tableView(_:heightForRowAt:)

2 ответа

Решение

tl;dr вам нужно добавить префикс объявления функции к объявлению Objective-C, например

@objc(tableView:heightForRowAtIndexPath:)
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
  // return stuff
}

Я был предупрежден о том, что это решение, благодаря Руководству по миграции Swift 3, в котором говорится:

Если вы реализуете необязательное требование протокола Objective C в подклассе класса, который объявляет соответствие, вы увидите предупреждение: "Метод экземпляра"… "почти соответствует необязательному требованию"… "протокола"… ".

• Обходной путь: добавьте @objc(objectiveC:name:) атрибут перед реализацией необязательного требования с оригинальным селектором Objective-C внутри.

Я вполне уверен, что это ошибка: кажется, что динамизм во время выполнения, который позволяет проверять возможности селектора, не соединяется должным образом в Grand Swift Renaming, когда метод протокола находится в подклассе. Префикс объявления функции с именем Objective-C правильно соединяет Swift с Objective-C и позволяет запрашивать переименованные методы Swift 3 с помощью canPerformAction:withSender: изнутри Objective-C

Кажется, это исправлено в Swift 3.0.1 для обычных подклассов, но не исправлено для общих подклассов:

class A: NSObject, UITableViewDelegate {}

class B: A {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
}

class C<T>: A {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
}

print(#selector(B.tableView(_:didSelectRowAt:))) // tableView:didSelectRowAtIndexPath:
print(#selector(C<Int>.tableView(_:didSelectRowAt:))) // tableView:didSelectRowAt:

Смотрите: https://bugs.swift.org/browse/SR-2817

Чтобы это исправить: /questions/17433804/neobyazatelnyij-metod-protokola-swift-3-objc-v-podklasse/17433808#17433808

@objc(tableView:heightForRowAtIndexPath:)
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
  // return stuff
}
Другие вопросы по тегам