Swift 3中ObjC可选协议方法在子类中未被调用

14

我有以下类层次结构:

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

实现了一个UITableViewDelegate协议方法,例如tableView:willDisplayCellAt:

在我的类SpecificScrollableViewController中,它继承自ScrollableViewController,新的可选协议方法不再被调用,例如tableView(_:heightForRowAt:)

2个回答

38

简而言之,您需要在函数声明前加上其Objective-C声明,例如:

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

感谢Swift 3 迁移指南,向我透露了这个解决方案:

如果您在声明符合协议的类的子类中实现可选的 Objective-C 协议要求,则会看到警告:“Instance method ‘…’ nearly matches optional requirement ‘…’ of protocol ‘…’”(实例方法'...'几乎与协议'...'的可选要求匹配)。

• 解决方法:在可选要求的实现之前添加 @objc(objectiveC:name:) 属性,并在其中使用原始 Objective-C 选择器。

我相当确定这是一个错误:似乎当协议方法在子类中时,允许检查选择器功能的运行时动态性没有在 Grand Swift Renaming 中得到正确桥接。在函数声明前加上 Objective-C 名称可以正确地将 Swift 桥接到 Objective-C,并允许在 Objective-C 内部使用 canPerformAction:withSender: 查询 Swift 3 重命名方法。


1
@cgossain 我很高兴能帮忙!在找到它之前,我苦恼了6个小时 :( - Alex Popov
你可以在函数前面加上 private 来消除警告。 - rashfmnb
2
如果使用了 @rashfmnb,你会得到一个“向未识别的实例发送选择器”错误。 - Slayter
嗨@AlexPopov,我正在使用预定的解决方案,但它在Xcode 8.3上无效。 `@optional
  • (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didFinishPickingAssets:(NSArray *)assets; 是Objective-C协议。 我已经实现了协议,如下:@objc(qb_imagePickerController:didFinishPickingAssets:) func qb_imagePickerController(_ imagePickerController: QBImagePickerController, didFinishPickingAssets assets: [AnyObject])`。但是,警告仍然出现。
- Milan Kamilya
2
这似乎在 Xcode 9.0.1 iOS 11 中的可选协议方法中仍然存在。 - Damo

3

这个问题在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://dev59.com/MFkS5IYBdhLWcg3w05eT#39416386

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接