Ricerca…


Osservazioni

Per ulteriori informazioni, consultare la documentazione di Apple sull'utilizzo di Swift con Cocoa e Objective-C .

Utilizzo delle classi Swift dal codice Objective-C

Nello stesso modulo

All'interno di un modulo chiamato " MyModule ", Xcode genera un'intestazione denominata MyModule-Swift.h che espone le classi Swift pubbliche a Objective-C. Importa questa intestazione per utilizzare le classi 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

Impostazioni di costruzione rilevanti:

  • Nome intestazione interfaccia Objective-C : controlla il nome dell'intestazione Obj-C generata.
  • Installa Intestazione di compatibilità Objective-C : se l'intestazione -Swift.h deve essere un'intestazione pubblica (per gli obiettivi del framework).

costruire lo screenshot delle impostazioni


In un altro modulo

Uso di @import MyFramework; importa l'intero modulo, comprese le interfacce Obj-C per le classi Swift (se è abilitata la suddetta impostazione di build).

Utilizzo delle classi Objective-C dal codice Swift

Se MyFramework contiene classi Objective-C nelle intestazioni pubbliche (e nell'intestazione dell'ombrello), quindi import MyFramework è tutto ciò che è necessario per utilizzarli da Swift.

Colpire le intestazioni

Un'intestazione di bridging rende visibili ulteriori dichiarazioni Objective-C e C al codice Swift. Quando si aggiungono file di progetto, Xcode può offrire di creare automaticamente un'intestazione di bridging:

finestra di dialogo per il collegamento a ponte

Per crearne uno manualmente, modifica l'impostazione di costruzione dell'intestazione di Bridging Objective-C :

inserisci la descrizione dell'immagine qui

All'interno dell'intestazione del bridging, importa qualsiasi file sia necessario utilizzare dal codice:

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

Interfaccia generata

Fai clic sul pulsante Elementi correlati (o premi ^ 1), quindi seleziona Interfaccia generata per visualizzare l'interfaccia Swift che verrà generata da un'intestazione Objective-C.

Specifica un'intestazione di bridging per swiftc

Il -import-objc-header specifica un'intestazione per l'importazione da swiftc :

// 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)

Utilizzare una mappa modulo per importare intestazioni C

Una mappa modulo può semplicemente import mymodule configurandolo per leggere i file header C e farli apparire come funzioni Swift.

Inserire un file denominato module.modulemap in una directory denominata mymodule :

struttura della directory

All'interno del file di mappa del modulo:

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

Quindi import il modulo:

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

Usa il flag -I directory per dire a swiftc dove trovare il modulo:

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

Per ulteriori informazioni sulla sintassi della mappa dei moduli, consultare la documentazione Clang sulle mappe dei moduli .

Interoperabilità a grana fine tra Objective-C e Swift

Quando un'API è contrassegnata con NS_REFINED_FOR_SWIFT , verrà anteposta a due caratteri di sottolineatura ( __ ) se importati in Swift:

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

L' interfaccia generata si presenta così:

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

Ora puoi sostituire l'API con un'estensione più "Swifty". In questo caso, possiamo utilizzare un valore di ritorno opzionale , 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
}

Nella maggior parte dei casi potresti voler limitare o meno un argomento a una funzione Objective-C che potrebbe essere nil . Questo viene fatto usando la parola chiave _Nonnull , che qualifica qualsiasi riferimento a puntatore o blocco:

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

Con quello scritto, il compilatore deve emettere un errore ogni volta che proviamo a passare nil a quella funzione dal nostro codice Swift:

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

L'opposto di _Nonnull è _Nullable , il che significa che è accettabile passare nil in questo argomento. _Nullable è anche il valore predefinito; tuttavia, specificarlo consente esplicitamente un codice più auto-documentato e a prova di futuro.

Per aiutare ulteriormente il compilatore a ottimizzare il tuo codice, potresti anche voler specificare se il blocco sta eseguendo l'escape:

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

Con questo attributo promettiamo di non salvare il riferimento del blocco e di non chiamare il blocco dopo che la funzione ha terminato l'esecuzione.

Utilizzare la libreria standard C

L'interoperabilità di Swift's C consente di utilizzare funzioni e tipi dalla libreria standard C.

Su Linux, la libreria standard C viene esposta tramite il modulo Glibc ; sulle piattaforme Apple si chiama 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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow