Swift 3 ObjC 可选协议方法未在子类中调用
Swift 3 ObjC Optional Protocol Method Not Called in Subclass
我有以下 class 层次结构:
class ScrollableViewController: UIViewController, UITableViewDelegate { // ... }
实现一个 UITableViewDelegate
协议方法,例如tableView:willDisplayCellAt:
在我的 class SpecificScrollableViewController
中,它继承自 ScrollableViewController
,不再调用新的可选协议方法,例如tableView(_:heightForRowAt:)
tl;dr 您需要在函数声明前加上 Objective-C 声明前缀,例如
@objc(tableView:heightForRowAtIndexPath:)
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// return stuff
}
由于 Swift 3 Migration Guide 指出:
,我被告知这是一个解决方案
If you implement an optional Objective-C protocol requirement in a subclass of a class that declares conformance, you’ll see a warning, “Instance method ‘…’ nearly matches optional requirement ‘…’ of protocol ‘…’”
• Workaround: Add an @objc(objectiveC:name:)
attribute before the implementation of the optional requirement with the original Objective-C selector inside.
我相当确定这是一个错误:似乎允许检查选择器功能的运行时动态在 Grand Swift 当协议方法在子类中时重命名时没有得到正确桥接.使用 Objective-C 名称作为函数声明的前缀可以正确地将 Swift 桥接到 Objective-C 并允许 Swift 3 个重命名的方法可以从 [=21] 中使用 canPerformAction:withSender:
查询=]
这似乎已在 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
修复它:
@objc(tableView:heightForRowAtIndexPath:)
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// return stuff
}
我有以下 class 层次结构:
class ScrollableViewController: UIViewController, UITableViewDelegate { // ... }
实现一个 UITableViewDelegate
协议方法,例如tableView:willDisplayCellAt:
在我的 class SpecificScrollableViewController
中,它继承自 ScrollableViewController
,不再调用新的可选协议方法,例如tableView(_:heightForRowAt:)
tl;dr 您需要在函数声明前加上 Objective-C 声明前缀,例如
@objc(tableView:heightForRowAtIndexPath:)
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// return stuff
}
由于 Swift 3 Migration Guide 指出:
,我被告知这是一个解决方案If you implement an optional Objective-C protocol requirement in a subclass of a class that declares conformance, you’ll see a warning, “Instance method ‘…’ nearly matches optional requirement ‘…’ of protocol ‘…’”
• Workaround: Add an
@objc(objectiveC:name:)
attribute before the implementation of the optional requirement with the original Objective-C selector inside.
我相当确定这是一个错误:似乎允许检查选择器功能的运行时动态在 Grand Swift 当协议方法在子类中时重命名时没有得到正确桥接.使用 Objective-C 名称作为函数声明的前缀可以正确地将 Swift 桥接到 Objective-C 并允许 Swift 3 个重命名的方法可以从 [=21] 中使用 canPerformAction:withSender:
查询=]
这似乎已在 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
修复它:
@objc(tableView:heightForRowAtIndexPath:)
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// return stuff
}