在Objective-C和Swift之间进行细粒度的互操作
示例
将API标记为时NS_REFINED_FOR_SWIFT,将其__导入Swift时将以两个下划线()作为前缀:
@interface MyClass : NSObject - (NSInteger)indexOfObject:(id)obj NS_REFINED_FOR_SWIFT; @end
生成的界面如下所示:
public class MyClass : NSObject { public func __indexOfObject(obj: AnyObject) -> Int }
现在,您可以使用更“Swifty”扩展名替换API。在这种情况下,我们可以使用可选的返回值,过滤掉NSNotFound:
extension MyClass { //如果对象不存在,则不返回NSNotFound, //此“精炼”API返回nil。"refined" API returns nil. func indexOfObject(obj: AnyObject) -> Int? { let idx = __indexOfObject(obj) if idx == NSNotFound { return nil } return idx } } //Swift代码,应使用“iflet”:"if let" as it should be: let myobj = MyClass() if let idx = myobj.indexOfObject(something) { //用idx做某事 }
在大多数情况下,您可能想限制是否可以将Objective-C函数的参数设为nil。这可以通过使用_Nonnull关键字来完成,该关键字可以限定任何指针或块引用:
void doStuff(const void *const _Nonnull data, void (^_Nonnull completion)()) { //复杂的异步代码 }
编写该nil代码后,每当我们尝试从Swift代码传递给该函数时,编译器都会发出错误:
doStuff( nil, //错误:nil与预期的参数类型'UnsafeRawPointer'不兼容 nil) // error: nil is not compatible with expected argument type '() -> Void'
相反的_Nonnull是_Nullable,这表示传递nil此参数是可以接受的。_Nullable也是默认值;但是,明确指定它可以使用更多的自成体系的代码和面向未来的代码。
为了进一步帮助编译器优化代码,您可能还需要指定代码是否在转义:
void callNow(__attribute__((noescape)) void (^_Nonnull f)()) { //f没有存储在任何地方 }
使用此属性,我们保证在函数完成执行后不保存块引用,也不调用该块。