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
}
使用此屬性,我們保證不會儲存塊引用,也不會在函式執行完畢後呼叫塊。