Swift Language Interoperación de grano fino entre Objective-C y Swift


Ejemplo

Cuando una API está marcada con NS_REFINED_FOR_SWIFT , tendrá un prefijo con dos guiones bajos ( __ ) cuando se importe a Swift:

@interface MyClass : NSObject
- (NSInteger)indexOfObject:(id)obj NS_REFINED_FOR_SWIFT;
@end

La interfaz generada se ve así:

public class MyClass : NSObject {
    public func __indexOfObject(obj: AnyObject) -> Int
}

Ahora puedes reemplazar la API con una extensión más "Swifty". En este caso, podemos usar un valor de retorno opcional , filtrando 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
}

En la mayoría de los casos, es posible que desee restringir si un argumento a una función de Objective-C podría ser nil . Esto se hace usando la palabra clave _Nonnull , que califica cualquier puntero o referencia de bloque:

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

Con eso escrito, el compilador emitirá un error cada vez que intentemos pasar nil a esa función desde nuestro código Swift:

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

El opuesto de _Nonnull es _Nullable , lo que significa que es aceptable pasar nil en este argumento. _Nullable también es el valor predeterminado; sin embargo, especificarlo explícitamente permite un código más auto documentado y preparado para el futuro.

Para ayudar aún más al compilador a optimizar su código, es posible que también desee especificar si el bloque está escapando:

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

Con este atributo, prometemos no guardar la referencia de bloque y no llamar al bloque después de que la función haya finalizado su ejecución.