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
}
使用此属性,我们保证不会保存块引用,也不会在函数执行完毕后调用块。