Buscar..


Observaciones

Para obtener más información, consulte la documentación de Apple sobre el uso de Swift con Cocoa y Objective-C .

Usando clases Swift desde el código Objective-C

En el mismo modulo

Dentro de un módulo llamado " MyModule ", Xcode genera un encabezado llamado MyModule-Swift.h que expone las clases públicas de Swift a Objective-C. Importe este encabezado para usar las clases Swift:

// MySwiftClass.swift in MyApp
import Foundation

// The class must be `public` to be visible, unless this target also has a bridging header
public class MySwiftClass: NSObject {
    // ...
}
// MyViewController.m in MyApp

#import "MyViewController.h"
#import "MyApp-Swift.h"                    // import the generated interface
#import <MyFramework/MyFramework-Swift.h>  // or use angle brackets for a framework target

@implementation MyViewController
- (void)demo {
    [[MySwiftClass alloc] init];  // use the Swift class
}
@end

Configuraciones de construcción relevantes:

  • Nombre de encabezado de interfaz generado por Objective-C : controla el nombre del encabezado Obj-C generado.
  • Instale el encabezado de compatibilidad de Objective-C : si el encabezado -Swift.h debe ser un encabezado público (para los destinos del marco).

configuración de construcción captura de pantalla


En otro modulo

Utilizando @import MyFramework; importa todo el módulo, incluidas las interfaces Obj-C a las clases Swift (si la configuración de compilación antes mencionada está habilitada).

Usando las clases de Objective-C del código Swift

Si MyFramework contiene clases de Objective-C en sus encabezados públicos (y el encabezado general), entonces import MyFramework es todo lo necesario para usarlos desde Swift.

Puente de encabezados

Un encabezado puente hace que las declaraciones de Objective-C y C adicionales sean visibles para el código Swift. Al agregar archivos de proyecto, Xcode puede ofrecer crear un encabezado de puente automáticamente:

puente de encabezado de diálogo

Para crear uno manualmente, modifique la configuración de compilación del encabezado de puente de Objective-C :

introduzca la descripción de la imagen aquí

Dentro del encabezado puente, importe los archivos que sean necesarios para usar desde el código:

// MyApp-Bridging-Header.h
#import "MyClass.h"  // allows code in this module to use MyClass

Interfaz generada

Haga clic en el botón Elementos relacionados (o presione ⌃1), luego seleccione Interfaz generada para ver la interfaz Swift que se generará desde un encabezado de Objective-C.

Especifique un encabezado de puente para swiftc

El -import-objc-header especifica un encabezado para que swiftc importe:

// defs.h
struct Color {
    int red, green, blue;
};

#define MAX_VALUE 255
// demo.swift
extension Color: CustomStringConvertible {  // extension on a C struct
    public var description: String {
        return "Color(red: \(red), green: \(green), blue: \(blue))"
    }
}
print("MAX_VALUE is: \(MAX_VALUE)")  // C macro becomes a constant
let color = Color(red: 0xCA, green: 0xCA, blue: 0xD0)  // C struct initializer
print("The color is \(color)")
$ swiftc demo.swift -import-objc-header defs.h && ./demo
MAX_VALUE is: 255
The color is Color(red: 202, green: 202, blue: 208)

Usa un mapa de módulo para importar encabezados C

Un mapa de módulo puede simplemente import mymodule configurándolo para leer los archivos de encabezado C y hacer que aparezcan como funciones Swift.

Coloque un archivo llamado module.modulemap dentro de un directorio llamado mymodule :

estructura de directorios

Dentro del archivo del mapa del módulo:

// mymodule/module.modulemap
module mymodule {
    header "defs.h"
}

Luego import el módulo:

// demo.swift
import mymodule
print("Empty color: \(Color())")

Utilice el indicador de -I directory para indicar a swiftc dónde encontrar el módulo:

swiftc -I . demo.swift   # "-I ." means "search for modules in the current directory"

Para obtener más información sobre la sintaxis del mapa de módulos, consulte la documentación de Clang sobre mapas de módulos .

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

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.

Usa la biblioteca estándar de C

La interoperabilidad C de Swift le permite usar funciones y tipos de la biblioteca estándar C.

En Linux, la biblioteca estándar de C se expone a través del módulo Glibc ; en las plataformas de Apple se llama Darwin .

#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
import Darwin
#elseif os(Linux)
import Glibc
#endif

// use open(), read(), and other libc features


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow