Swift类的类方法在OC类调用报错:No known class method for selector
看起来你在Xcode新版本里遇到了Swift类方法无法被Objective-C调用的问题,之前旧版本正常,这大概率是因为Xcode升级后,Swift与Objective-C的桥接规则变得更严格了。咱们一步步来解决:
1. 显式标记Swift类型和方法为@objc
新版本的Swift对于需要暴露给Objective-C的类型和方法,要求更明确的标记。你需要做两处修改:
调整闭包类型别名
你的LoginCompletionHandler使用了匿名参数(_: Bool),这种写法在Objective-C里无法被正确识别,同时需要添加@objc标记:
@objc typealias LoginCompletionHandler = (Bool) -> Void
给类方法添加@objc修饰符
确保你的类方法被明确标记为可被Objective-C调用:
@objc class func showOnNavigation(navigationController: UINavigationController, completionBlock:@escaping LoginCompletionHandler) { let vc = SCLoginViewController(nibName: "SCLoginViewController", bundle: nil) vc.myLoginCompletionBlock = completionBlock navigationController.pushViewController(vc, animated: true) }
2. 清理项目缓存并重新构建
有时候Xcode的DerivedData缓存会导致桥接文件Project-Swift.h没有更新,执行以下操作:
- 清理项目:按下
Cmd + Shift + K - 清理构建文件夹:按下
Cmd + Option + Shift + K - 手动删除DerivedData文件夹(路径一般是
~/Library/Developer/Xcode/DerivedData/),然后重新打开项目并构建
3. 验证Project-Swift.h文件
构建完成后,打开Project-Swift.h文件(可以在Objective-C文件里按住Cmd点击导入的#import "Project-Swift.h"跳转过去),确认SCLoginViewController的类方法是否已经被正确生成,应该能看到类似这样的声明:
+ (void)showOnNavigationWithNavigationController:(UINavigationController * _Nonnull)navigationController completionBlock:(void (^ _Nonnull)(BOOL))completionBlock;
如果能看到这个声明,说明桥接成功,此时再去Objective-C里调用方法就不会报错了。
为什么旧版本Xcode没问题?
Xcode 10.1及以下的Swift版本(对应Swift 4.2及更早)对桥接的规则更宽松,会自动将继承自NSObject的类的方法和部分类型暴露给Objective-C。但从Xcode 11(Swift 5+)开始,苹果收紧了自动桥接的逻辑,需要显式添加@objc标记才能确保类型和方法被Objective-C识别。
内容的提问来源于stack exchange,提问作者Tapash Mollick

