在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代码,应使用“ if let”:"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没有存储在任何地方
}

使用此属性,我们保证在函数完成执行后不保存块引用,也不调用该块。