¿Cómo llamo al código Objective-C desde Swift?

974

En Swift, ¿cómo se llama el código Objective-C?

Apple mencionó que podrían coexistir en una aplicación, pero ¿significa esto que técnicamente se podrían reutilizar las clases antiguas hechas en Objective-C mientras se crean nuevas clases en Swift?

David Mulder
fuente
13
Consulte la guía de Apple para usar Swift con Cocoa y Objective-C .
rickster
10
Es interesante que esta pregunta obtenga tantos votos positivos y una recompensa. Cuando lo vi por primera vez, pensé: RTFM. Como se plantea, realmente no muestra ninguna investigación, ya que actualmente solo hay dos o tres recursos que documentan oficialmente a Swift, y uno de ellos está totalmente dedicado a esto exactamente (y está vinculado en el primer comentario).
Archivo analógico
66
@EvolGate: ¿qué es exactamente lo que falta en el Objetivo C que le impide ser un lenguaje independiente de la plataforma? El idioma y las bibliotecas estándar de idiomas son de código abierto. Puede usar Objective C en y para Windows, Os X, Linux, BSD, Solaris y cualquier otra plataforma compatible con GCC o LLVM. Puede portar fácilmente Objective C a cualquier plataforma con un compilador decente de C, incluso si no es compatible con GCC ni LLVM. No veo cómo podría ser más independiente de la plataforma que esto.
Archivo analógico
2
@DavidMulder: ¿Todavía se necesita la sección "El razonamiento"?
franck

Respuestas:

1395

Uso de clases de Objective-C en Swift

Si tiene una clase existente que le gustaría usar, realice el Paso 2 y luego salte al Paso 5 . (En algunos casos, tuve que agregar un #import <Foundation/Foundation.harchivo explícito a un archivo Objective-C anterior).

Paso 1: Agregar implementación de Objective-C - .m

Agregue un .marchivo a su clase y asígnele un nombre CustomObject.m.

Paso 2: Agregar encabezado de puente

Al agregar su .marchivo, es probable que reciba un mensaje similar al siguiente:

Un diálogo de estilo de hoja de macOS de Xcode que le pregunta si desea "configurar un encabezado de puente de Objective-C"

Haga clic en !

Si no vio el mensaje o borró accidentalmente su encabezado de puente, agregue un nuevo .harchivo a su proyecto y asígnele un nombre <#YourProjectName#>-Bridging-Header.h.

En algunas situaciones, particularmente cuando se trabaja con marcos Objective-C, no se agrega una clase Objective-C explícitamente y Xcode no puede encontrar el enlazador. En este caso, cree su .harchivo nombrado como se mencionó anteriormente, luego asegúrese de vincular su ruta en la configuración del proyecto de destino de la siguiente manera:

Una animación que demuestra el párrafo anterior.

Nota:

Es una buena práctica vincular su proyecto usando la $(SRCROOT)macro para que si mueve su proyecto o trabaja con otros usando un repositorio remoto, todavía funcionará. $(SRCROOT)puede considerarse como el directorio que contiene su archivo .xcodeproj. Podría verse así:

$(SRCROOT)/Folder/Folder/<#YourProjectName#>-Bridging-Header.h

Paso 3: Agregue el encabezado Objective-C - .h

Agregue otro .harchivo y asígnele un nombre CustomObject.h.

Paso 4: construye tu clase Objective-C

En CustomObject.h

#import <Foundation/Foundation.h>

@interface CustomObject : NSObject

@property (strong, nonatomic) id someProperty;

- (void) someMethod;

@end

En CustomObject.m

#import "CustomObject.h"

@implementation CustomObject 

- (void) someMethod {
    NSLog(@"SomeMethod Ran");
}

@end

Paso 5: Agregar clase al encabezado de puente

En YourProject-Bridging-Header.h:

#import "CustomObject.h"

Paso 6: usa tu objeto

En SomeSwiftFile.swift:

var instanceOfCustomObject = CustomObject()
instanceOfCustomObject.someProperty = "Hello World"
print(instanceOfCustomObject.someProperty)
instanceOfCustomObject.someMethod()

No hay necesidad de importar explícitamente; para eso sirve el encabezado de puente.

Usando clases rápidas en Objective-C

Paso 1: crear una nueva clase Swift

Agregue un .swiftarchivo a su proyecto y asígnele un nombre MySwiftObject.swift.

En MySwiftObject.swift:

import Foundation

@objc(MySwiftObject)
class MySwiftObject : NSObject {

    @objc
    var someProperty: AnyObject = "Some Initializer Val" as NSString

    init() {}

    @objc
    func someFunction(someArg: Any) -> NSString {
        return "You sent me \(someArg)"
    }
}

Paso 2: Importar archivos Swift a la clase ObjC

En SomeRandomClass.m:

#import "<#YourProjectName#>-Swift.h"

El archivo: <#YourProjectName#>-Swift.hya debe crearse automáticamente en su proyecto, incluso si no puede verlo.

Paso 3: usa tu clase

MySwiftObject * myOb = [MySwiftObject new];
NSLog(@"MyOb.someProperty: %@", myOb.someProperty);
myOb.someProperty = @"Hello World";
NSLog(@"MyOb.someProperty: %@", myOb.someProperty);

NSString * retString = [myOb someFunctionWithSomeArg:@"Arg"];

NSLog(@"RetString: %@", retString);

Notas:

  1. Si la finalización del código no se comporta como espera, intente ejecutar una compilación rápida Rpara ayudar a Xcode a encontrar parte del código de Objective-C en un contexto Swift y viceversa.

  2. Si agrega un .swiftarchivo a un proyecto anterior y obtiene el error dyld: Library not loaded: @rpath/libswift_stdlib_core.dylib, intente reiniciar completamente Xcode .

  3. Si bien originalmente era posible usar clases Swift puras (no descendientes de NSObject) que son visibles para Objective-C usando el @objcprefijo, esto ya no es posible. Ahora, para ser visible en Objective-C, el objeto Swift debe ser una clase conforme NSObjectProtocol(la forma más fácil de hacerlo es heredar de NSObject), o debe estar enummarcado @objccon un valor sin formato de algún tipo entero como Int. Puede ver el historial de edición para un ejemplo de código Swift 1.x @objcsin estas restricciones.

Logan
fuente
55
Es importante que anote los métodos con @objc o los métodos Swift no serán visibles desde Objective-C.
Tomáš Linhart
29
Tienes razón. Solo necesita especificarlo si no utiliza objetos Cocoa. Para ser accesible y utilizable en Objective-C, una clase Swift debe ser descendiente de una clase Objective-C o debe estar marcada @objc.
Tomáš Linhart
2
@MarkusRautopuro - Lo obtuve desde aquí: developer.apple.com/library/prerelease/ios/documentation/Swift/… "
Logan
2
Ver también: WWDC 2014 Sesión 406: Integrando Swift con Objective-C
Stuart M
66
Si importa un marco de Objective C en Swift, asegúrese de importar todos los marcos de los que depende el marco de Obj C en su proyecto (en Fases de compilación -> Enlace binario con bibliotecas), luego agregue # import para aquellos a un archivo de encabezado de prefijo, que debe agregarse a su proyecto en la configuración de compilación (en el campo Encabezado de prefijo). Esto incluye marcos como UIKit y Foundation, incluso si ya se usan desde Swift. Esto me hizo tropezar durante horas, y nadie parece haber documentado estos pasos.
user1021430
121

Consulte la guía de Apple para usar Swift con Cocoa y Objective-C . Esta guía cubre cómo usar el código Objective-C y C de Swift y viceversa y tiene recomendaciones sobre cómo convertir un proyecto o mezclar y combinar partes Objective-C / C y Swift en un proyecto existente.

El compilador genera automáticamente la sintaxis Swift para llamar a funciones C y métodos Objective-C. Como se ve en la documentación, este Objective-C:

UITableView *myTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];

se convierte en este código Swift:

let myTableView: UITableView = UITableView(frame: CGRectZero, style: .Grouped)

Xcode también hace esta traducción sobre la marcha: puede usar Abrir rápidamente mientras edita un archivo Swift y escribir un nombre de clase Objective-C, y lo llevará a una versión Swift-ified del encabezado de clase. (También puede obtener esto haciendo clic en un símbolo API en un archivo Swift). Y toda la documentación de referencia API en las bibliotecas de desarrollador iOS 8 y OS X v10.10 (Yosemite) está visible tanto en Objective-C como en Swift formas (por ejemplo UIView).

rickster
fuente
3
El enlace directo a la documentación de Apple sobre cómo integrar Swift en un proyecto existente: developer.apple.com/library/prerelease/ios/documentation/Swift/…
skywinder
Si está interesado en saber por qué se necesitan los archivos de encabezado y cómo se usa durante la fase de vinculación, asegúrese de leer este Manual Swift: Comprender la canalización de compilación Swift / Objective-C
Honey
62

Aquí hay instrucciones paso a paso para usar el código Objective-C (en este caso, un marco proporcionado por un tercero) en un proyecto Swift:

  1. Agregue cualquier archivo Objective-C a su proyecto Swift seleccionando File -> New -> New File -> Objective-C File. Al guardar, Xcode le preguntará si desea agregar un encabezado de puente . Elige ' '. (fuente: derrrick.com )Gif: agregar un archivo vacío al proyecto y generar un encabezado de puente

En simples pasos:

  1. Aparece un mensaje y luego haga clic en Aceptar ... Si no aparece, lo creamos manualmente como en el siguiente ... Cree un archivo de encabezado desde la fuente de iOS y déle el nombre ProjectName-Bridging-Header (ejemplo: Prueba -Bridging-Header), y luego vaya a la configuración de compilación en el código del compilador Swift -> Objective-C bridge agregue Objective-C bridge name .. (Test / Test-Bridging-Header.h). Sí, eso está completo.

  2. Opcionalmente, elimine el archivo Objective-C que agregó (denominado "cualquier cosa" en la imagen GIF anterior). No lo necesitas más.

  3. Abra el archivo de encabezado de puente : el nombre del archivo tiene la forma [YourProject] -Bridging-Header.h . Incluye un comentario proporcionado por Xcode. Agregue una línea de código para el archivo Objective-C que desea incluir , como un marco de terceros. Por ejemplo, para agregar Mixpanel a su proyecto, deberá agregar la siguiente línea de código al archivo de encabezado de puente:

    #import "Mixpanel.h"
  4. Ahora, en cualquier archivo Swift, puede usar el código Objective-C existente, en la sintaxis Swift (en el caso de este ejemplo, y puede llamar a los métodos del SDK de Mixpanel, etc.). Debe familiarizarse con la forma en que Xcode traduce Objective-C a Swift. La guía de Apple es una lectura rápida. O vea esta respuesta para un resumen incompleto.

Ejemplo para Mixpanel:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    Mixpanel.sharedInstanceWithToken("your-token")
    return true
}

¡Eso es!

Nota: Si elimina el archivo de encabezado de puente de su proyecto , asegúrese de ir a Configuración de compilación y elimine el valor de " Encabezado de puente de Objective-C " en "Compilador rápido - Generación de código".

torre de perforación
fuente
39

Puedes leer la bonita publicación Swift & Cocoapods . Básicamente, necesitamos crear un archivo de encabezado de puente y colocar todos los encabezados de Objective-C allí. Y luego necesitamos hacer referencia a él desde nuestra configuración de compilación. Después de eso, podemos usar el código Objective-C.

let manager = AFHTTPRequestOperationManager()
manager.GET(
  "http://example.com/resources.json",
  parameters: nil,
  success: { (operation: AFHTTPRequestOperation!,
              responseObject: AnyObject!) in
      println("JSON: " + responseObject.description)
  },
  failure: { (operation: AFHTTPRequestOperation!,
              error: NSError!) in
      println("Error: " + error.localizedDescription)
  })

También eche un vistazo al documento de Apple Usando Swift con Cocoa y Objective-C también.

Jake Lin
fuente
25

Escribí un proyecto simple de Xcode 6 que muestra cómo mezclar C ++, Objective-C y código Swift:

https://github.com/romitagl/shared/tree/master/C-ObjC-Swift/Performance_Console

En particular, el ejemplo llama a una función Objective-C y C ++ desde Swift .

La clave es crear un encabezado compartido, Project-Bridging-Header.h, y colocar los encabezados de Objective-C allí.

Descargue el proyecto como un ejemplo completo.

Gian Luigi Romita
fuente
24

Una cosa más que me gustaría agregar aquí:

Estoy muy agradecido por la respuesta de @ Logan. Ayuda mucho crear un archivo puente y configuraciones.

Pero después de hacer todos estos pasos, todavía no obtengo una clase Objective-C en Swift.

Usé la cocoapodsbiblioteca y la integré en mi proyecto. Lo cual es pod "pop".

Entonces, si está utilizando vainas de Objective-C en Swift, entonces puede haber una posibilidad de que no pueda acceder a importlas clases o Swift.

Lo simple que tienes que hacer es:

  1. Ir al <YOUR-PROJECT>-Bridging-Headerarchivo y
  2. Reemplace la declaración #import <ObjC_Framework>para@import ObjC_Framework

Por ejemplo: (biblioteca pop)

Reemplazar

#import <pop/POP.h>

con

@import pop;

Úselo clang importcuando #importno esté funcionando.

Kampai
fuente
Use la importación clang cuando #import no funciona. ¿Qué? ¡No acabo de decir que deberíamos usar @import?!
Miel
22

Cita de la documentación :

Cualquier marco Objective-C (o biblioteca C) que sea accesible como módulo puede importarse directamente a Swift. Esto incluye todos los marcos del sistema Objective-C, como Foundation, UIKit y SpriteKit, así como las bibliotecas C comunes que se proporcionan con el sistema. Por ejemplo, para importar Foundation, simplemente agregue esta declaración de importación en la parte superior del archivo Swift en el que está trabajando:

import Foundation

Esta importación hace que todas las API de Foundation, incluidas NSDate, NSURL, NSMutableData y todos sus métodos, propiedades y categorías, estén disponibles directamente en Swift.

Gergo Erdosi
fuente
12

Solo una nota para quien intente agregar una biblioteca Objective-C a Swift: debe agregar -ObjC en Configuración de compilación -> Vinculación -> Otras banderas de vinculador .

david72
fuente
¿Por qué? Agregue información sobre lo que hace este indicador y por qué debe agregarse.
Johan Karlsson
9

Después de crear un encabezado de puente, vaya a Configuración de compilación => Buscar "Encabezado de puente de Objective-C".

Justo debajo encontrará el archivo "" Nombre de encabezado de interfaz generado por Objective-C ".

Importe ese archivo en su controlador de vista.

Ejemplo: en mi caso: "Dauble-Swift.h"

eEter descripción de la imagen aquí

Avijit Nagare
fuente
5

Haga clic en el menú Nuevo archivo y elija el idioma de selección de archivos Objetivo. En ese momento, genera automáticamente un archivo "Encabezado de puente de Objective-C" que se utiliza para definir algún nombre de clase.

"Encabezado de puente Objective-C" en "Compilador rápido - Generación de código".

Yogesh Shelke
fuente
3
  1. Cree un archivo .h desde NewFile -> Fuente -> archivo de encabezado
  2. A continuación, guarde el nombre del archivo Your_Target_Name-Bridging-Header.h La gente aquí se equivoca al tomar el nombre de su proyecto, pero debería ser el nombre del objetivo del proyecto si en caso de que ambos sean diferentes, generalmente son iguales.
  3. Luego, en la configuración de compilación, busque el indicador de encabezado de puente de Objective-C y coloque la dirección de su archivo de puente recién creado, puede hacerlo haciendo clic derecho en el archivo -> mostrar en el buscador -> arrastre el archivo en el área de texto y luego la dirección aparecerá ser poblado
  4. Usando #import Your_Objective-C_file.h
  5. En el archivo swift puede acceder al archivo ObjC pero solo en lenguaje swift.
Nish
fuente
3

ingrese la descripción de la imagen aquíHe agregado el proyecto en github que incluye una pequeña muestra para llamar rápidamente al código objetivo c.

Llame a la clase ObjectiveC desde swift

CrazyPro007
fuente
NOTA: - Cuando crea una clase Objc en un proyecto rápido, xcode le pide que puentee la clase automáticamente. No te preocupes :)
CrazyPro007
3

En el proyecto Swift 4.2.1 en Xcode 10.1 puede agregar fácilmente el archivo Objective-C. Siga los pasos a continuación para conectar el archivo Objective-C al proyecto Swift.

Paso_01: Cree un nuevo proyecto Xcode usando el lenguaje Swift:

File> New> Project> objc.

Paso_02: en el proyecto Swift, agregue un nuevo archivo Objective-C:

File> New> File...> macOS> Objective-C File.

Paso_03: si agrega un nuevo archivo Objective-C al proyecto Swift por primera vez, Xcode le pregunta:

Would you like to configure an Objective-C bridging header?

ingrese la descripción de la imagen aquí

Paso_04: selecciona la opción:

Create Bridging Header.

Paso_05: se generará un archivo correspondiente con un nombre:

Objc-Bridging-Header.h.

ingrese la descripción de la imagen aquí

Paso_06: Ahora, necesita configurar la ruta del archivo Bridge en el encabezado del puente. En Project Navigator, haga clic en proyecto con nombre objcy luego elija:

Build Settings> Objective-C Bridging Header> Objc-Bridging-Header.h.

Paso_07: Arrastra y suelta tu Objc-Bridging-Header.hen ese cuadro para generar una ruta de archivo.

ingrese la descripción de la imagen aquí

Paso_08: Abra su Objc-Bridging-Header.harchivo e importe el archivo Objective-C que desea usar en su archivo Swift.

#import "SpecialObjcFile.m"

Aquí hay un contenido de SpecialObjcFile.m:

#import <Foundation/Foundation.h>

@interface Person: NSObject {
@public
    bool busy;
}
@property
    bool busy;
@end

Paso_09: ahora en su archivo Swift, puede usar una clase Objective-C:

override func viewDidLoad() {
    super.viewDidLoad()
    let myObjcContent = Person()
    print(myObjcContent.busy)
}

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

Andy
fuente
1

La respuesta de Logans funciona bien, excepto que en la última Swift 5da algún error de compilación. Aquí está la solución para las personas que trabajan en Swift 5.

Swift 5

import Foundation

class MySwiftObject : NSObject {

    var someProperty: AnyObject = "Some Initializer Val" as AnyObject

    override init() {}

    func someFunction(someArg:AnyObject) -> String {
        let returnVal = "You sent me \(someArg)"
        return returnVal
    }
}
Sazzad Hissain Khan
fuente
1

Rápido consumidor, productor de Objective-C

  1. Agregar un encabezado .hy .marchivos de implementación : archivo de clase Cocoa (Objective-C)
    Por ejemploMyFileName

  2. configurar el encabezado de puente
    Cuando vea Would you like to configure an Objective-C bridging headerclic -

    • <target_name>-Bridging-Header.h se generará automáticamente
    • Configuración de compilación -> Encabezado de puente de Objective-C
  3. Agregar clase a Bridging-Header
    En <target_name>-Bridging-Header.hagregar una línea#import "<MyFileName>.h"

PD: si debe agregar archivos Objective-C existentes en el proyecto Swift, agregue de Bridging-Header.hantemano

Objetivo-C consumidor, productor de Swift

  1. Agrega un <MyFileName>.swifty extiendeNSObject

  2. Importar archivos Swift a ObjC Class
    Agregar #import "<#YourProjectName#>-Swift.h"a su archivo Objective-C

  3. Marcar el código público de Swift [@objc y @objcMembers]

yoAlex5
fuente
0

Apple ha proporcionado una guía oficial en este documento: cómo-llamar-objetivo-c-código-de-rápido

Aquí está la parte relevante:

Para importar un conjunto de archivos Objective-C en el código Swift dentro del mismo objetivo de la aplicación, debe confiar en un archivo de encabezado de puente Objective-C para exponer esos archivos a Swift . Xcode ofrece crear este encabezado cuando agrega un archivo Swift a una aplicación Objective-C existente, o un archivo Objective-C a una aplicación Swift existente.

Si acepta, Xcode crea el archivo de encabezado de puente junto con el archivo que estaba creando y lo nombra usando el nombre del módulo del producto seguido de "-Bridging-Header.h". Alternativamente, puede crear un encabezado puente usted mismo seleccionando Archivo> Nuevo> Archivo> [sistema operativo]> Fuente> Archivo de encabezado

Edite el encabezado de puente para exponer su código Objective-C a su código Swift:

  1. En su encabezado de puente de Objective-C, importe cada encabezado de Objective-C que desee exponer a Swift .
  2. En Configuración de compilación, en Swift Compiler - Generación de código, asegúrese de que la configuración de compilación de Encabezado de puente de Objective-C tenga una ruta al archivo de encabezado de puente. La ruta debe ser relativa a su proyecto, similar a la forma en que se especifica su ruta Info.plist en Configuración de compilación. En la mayoría de los casos, no necesitará modificar esta configuración.

Swift puede ver todos los encabezados públicos de Objective-C que figuran en el encabezado de puente.

Tibin Thomas
fuente
0

Enfoque de dos vías para usar el objetivo-c objetivo-c

1

  1. Crear archivo bridge-header.h en Xcode Project
  2. importar el archivo .h en el archivo de encabezado de puente
  3. Establecer la ruta del puente-encabezado en la configuración de compilación.
  4. Limpiar el proyecto

2

  1. Cree archivos Objective-C en el proyecto (establece automáticamente la ruta en la configuración de compilación)
  2. importar el archivo .h en el archivo de encabezado de puente

Ahora bien para ir Gracias

Sanjay Mali
fuente