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 {
    // Rather than returning NSNotFound if the object doesn't exist,
    // this "refined" API returns nil.
    func indexOfObject(obj: AnyObject) -> Int? {
        let idx = __indexOfObject(obj)
        if idx == NSNotFound { return nil }
        return idx
    }
}

// Swift code, using "if let" as it should be:
let myobj = MyClass()
if let idx = myobj.indexOfObject(something) {
    // do something with idx
}

在大多数情况下,你可能希望限制 Objective-C 函数的参数是否为 nil。这是使用 _Nonnull 关键字完成的,该关键字限定任何指针或块引用:

void
doStuff(const void *const _Nonnull data, void (^_Nonnull completion)())
{
    // complex asynchronous code
}

编写完成后,只要我们尝试将 nil 从 Swift 代码传递给该函数,编译器就会发出错误:

doStuff(
    nil,  // error: nil is not compatible with expected argument type 'UnsafeRawPointer'
    nil)  // error: nil is not compatible with expected argument type '() -> Void'

_Nonnull 相反的是 _Nullable,这意味着在此论证中传递 nil 是可以接受的。_Nullable 也是默认值; 但是,明确指定它可以提供更多自我记录和面向未来的代码。

为了进一步帮助编译器优化代码,你还可能需要指定块是否转义:

void
callNow(__attribute__((noescape)) void (^_Nonnull f)())
{
    // f is not stored anywhere
}

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