本文主要闲聊一些 Objective-C 和 Swift 混编项目带来的一些潜规则,但愿能帮到对此感到疑惑的朋友。下面咱们开始进入主题:objective-c
官方 Guide 上只是简单叙述(Using Swift with Cocoa and Objective-C),即 Swift 编译器会在咱们使用 Objective-C 的 API 时自动的将其转成 Swift 风格的 API(说白了就是会对一些方法名、枚举名等等作一些有规则的删减,即重命名)。swift
在 Swift 中引用 Objective-C 单例时,若是单例方法包含于类名,则会出现编译错误,下面咱们来看几个例子。bash
@interface TXLocationManager : NSObject
+ (instancetype)manager;
@end
复制代码
TXLoginManager
类有一个单例方法命名为 manager,在 Swift 中引用 manager 方法时,会出现编译错误:ide
说白了,manager 方法已经废了。。。ui
在 Example 1 的基础上,咱们把单例方法的命名改一改:spa
@interface TXLocationManager : NSObject
+ (instancetype)shareInstance;
@end
复制代码
单例方法命名改为 shareInstance 后,编译经过了。至此,至少问题已经解决了,如今咱们再简单看看是什么缘由?为什么 manager 方法没法引用,而 shareInstance 却能够引用呢?3d
在 Example 1 的基础上,把 manager 单例方法名称改成 shareManager :code
@interface TXLocationManager : NSObject
+ (instancetype)shareManager;
@end
复制代码
咱们能够发如今 Swift 中引用时,shareManager 方法名被重命名为 share :cdn
至此,咱们能够得出一个简单的命名潜规则:在 Swift 中引用 Objective-C 单例时,若是单例方法包含于类名,则会出现编译错误,准确的说,应该是若是单例方法的名称正好是该类名驼峰命名的后缀,那么在 Swift 中引用该单例方法时,会出现编译错误。对象
为什么在 Swift 中引用 Objective-C 类的 API 会出现这种问题呢?官方 Guide 上时这样描述的:
The Swift compiler automatically imports Objective-C code as conventional Swift code. It imports Objective-C class factory methods as Swift initializers, and Objective-C enumeration cases truncated names.
由于 Swift 编译器在使用 Objective-C 的代码时会自动的将其转成 Swift 风格的代码,就是会对一些方法名、枚举名等等作一些有规则的删减。
There may be edge cases in your code that are not automatically handled. If you need to change the name imported by Swift of an Objective-C method, enumeration case, or option set value, you can use the NS_SWIFT_NAME macro to customize how a declaration is imported.
根据官方 Guide,上述的这种 case 属于 特殊的状况。那如何解决这种问题呢,Swift 提供了一个宏,专门处理咱们遇到的这种 case —— NS_SWIFT_NAME
@interface TXLocationManager : NSObject
+ (instancetype)manager NS_SWIFT_NAME(shareInstance());
@end
复制代码
这样,manager 该单例方法,当咱们在 Swift 中引用时,会被重命名为 shareInstance。
let _ = TXLocationManager.shareInstance()
复制代码
有时候,咱们在 Swift 中引用 Objective-C 中某个类的 API 时,方法名是可能会被重命名的,下面咱们直接看例子。
@interface TXLocationManager : NSObject
+ (instancetype)managerWithCoordinateY:(CGFloat)y
// Or
// + (TXLocationManager *)managerWithCoordinateY:(CGFloat)y
@end
复制代码
当该类的类方法返回自身类型的实例对象时,上述的方法会被重命名。应该这样引用:
// 方式一:
let _ = TXLocationManager.init(coordinateY: 9)
// 方式二:
let _ = TXLocationManager(coordinateY: 9)
// 错误引用方式,编译失败
let _ = TXLocationManager.manager(withCoordinateY: 9)
复制代码
经过上述实践,咱们能够发现类方法中的 manager 前缀会被删掉,并且变成了 Swift 中的 init 方法。若是该类的类方法不返回自身类型的实例对象呢?
@interface TXLocationManager : NSObject
+ (void)managerWithCoordinateY:(CGFloat)y;
// Or
// + (NSObject *)managerWithCoordinateY:(CGFloat)y;
// + (CGFloat)managerWithCoordinateY:(CGFloat)y;
@end
复制代码
经过实践能够发现,在 Swift 中是能够这样引用的:
TXLocationManager.manager(withCoordinateY: 9)
复制代码
这种方式的引用同咱们通常的方法引用是一致的,无异同。
实例方法的重命名规则与类方法有点类似,此处就再也不详述了,感兴趣的朋友能够本身实践一下。(固然方法的重命名咱们通常均可以经过 NS_SWIFT_NAME
来指定)