web-dev-qa-db-ja.com

Swift 3ObjCオプションのプロトコルメソッドがサブクラスで呼び出されない

次のクラス階層があります。

_class ScrollableViewController: UIViewController, UITableViewDelegate { // ... }
_

これは、1つのUITableViewDelegateプロトコルメソッドを実装します。 _tableView:willDisplayCellAt:_

SpecificScrollableViewControllerから継承する私のクラスScrollableViewControllerでは、新しいオプションのプロトコルメソッドはもう呼び出されません。 tableView(_:heightForRowAt:)

14
Alex Popov

tl; dr関数宣言の前にObjective-C宣言を付ける必要があります。例:.

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

Swift 3 Migration Guide のおかげで、これが解決策であることがわかりました。

適合を宣言するクラスのサブクラスにオプションのObjective-Cプロトコル要件を実装すると、「インスタンスメソッド「…」はプロトコル「…」のオプション要件「…」とほぼ一致します」という警告が表示されます。

•回避策:元のObjective-Cセレクターを内部に使用してオプション要件を実装する前に、@objc(objectiveC:name:)属性を追加します。

私はこれがバグであるとかなり確信しています:セレクター機能のチェックを可能にするランタイムダイナミズムがグランドで適切にブリッジされないようですSwiftプロトコルメソッドがサブクラスにあるときの名前の変更。関数宣言の前にObjective-C名を付けると、SwiftがObjective-Cに適切にブリッジされ、Swift 3つの名前が変更されたメソッドを内部からcanPerformAction:withSender:でクエリできるようになります。 Objective-C

36
Alex Popov

これは、通常のサブクラスでは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

それを修正するには: https://stackoverflow.com/a/39416386/1109892

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