Swift Language Working with C and Objective-C Fine-grained interoperation between Objective-C and Swift


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;

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:

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:

    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:

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.