When an API is marked with NS_REFINED_FOR_SWIFT
, it will be prefixed with two underscores (__
) when imported to Swift:
@interface MyClass : NSObject
- (NSInteger)indexOfObject:(id)obj NS_REFINED_FOR_SWIFT;
@end
The generated interface looks like this:
public class MyClass : NSObject {
public func __indexOfObject(obj: AnyObject) -> Int
}
Now you can replace the API with a more "Swifty" extension. In this case, we can use an optional return value, filtering out 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
}
In most cases you might want to restrict whether or not an argument to an Objective-C function could be nil
. This is done using _Nonnull
keyword, which qualifies any pointer or block reference:
void
doStuff(const void *const _Nonnull data, void (^_Nonnull completion)())
{
// complex asynchronous code
}
With that written, the compiler shall emit an error whenever we try to pass nil
to that function from our Swift code:
doStuff(
nil, // error: nil is not compatible with expected argument type 'UnsafeRawPointer'
nil) // error: nil is not compatible with expected argument type '() -> Void'
The opposite of _Nonnull
is _Nullable
, which means that it is acceptable to pass nil
in this argument. _Nullable
is also the default; however, specifying it explicitly allows for more self-documented and future-proof code.
To further help the compiler with optimising your code, you also might want to specify if the block is escaping:
void
callNow(__attribute__((noescape)) void (^_Nonnull f)())
{
// f is not stored anywhere
}
With this attribute we promise not to save the block reference and not to call the block after the function has finished execution.