Suche…


Bemerkungen

Weitere Informationen finden Sie in der Apple-Dokumentation zur Verwendung von Swift mit Cocoa und Objective-C .

Verwendung von Swift-Klassen aus Objective-C-Code

Im selben Modul

In einem Modul namens " MyModule " generiert Xcode einen Header mit dem Namen MyModule-Swift.h der öffentliche Swift-Klassen für Objective-C MyModule-Swift.h macht. Importieren Sie diesen Header, um die Swift-Klassen zu verwenden:

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

Relevante Build-Einstellungen:

  • Objective-C Generated Interface Header Name : Steuert den Namen des generierten Obj-C-Headers.
  • Installieren Sie Objective-C Compatibility Header : Gibt an, ob der Header -Swift.h ein öffentlicher Header sein soll (für Framework-Ziele).

Einstellungs-Screenshot erstellen


In einem anderen Modul

@import MyFramework; Importiert das gesamte Modul einschließlich der Obj-C-Schnittstellen in Swift-Klassen (wenn die oben genannte Build-Einstellung aktiviert ist).

Objective-C-Klassen aus Swift-Code verwenden

Wenn MyFramework in seinen öffentlichen Kopfzeilen Objective-C-Klassen (und den Umbrella-Header) enthält, müssen Sie nur import MyFramework , um sie aus Swift zu verwenden.

Überbrückung von Headern

Ein Bridging-Header macht zusätzliche Objective-C- und C-Deklarationen für den Swift-Code sichtbar. Beim Hinzufügen von Projektdateien bietet Xcode möglicherweise an, einen Bridging-Header automatisch zu erstellen:

Überbrückungskopfdialogfeld

Um einen manuell zu erstellen, ändern Sie die Build-Einstellung Objective-C Bridging Header :

Geben Sie hier die Bildbeschreibung ein

Importieren Sie im Bridging-Header die erforderlichen Dateien aus dem Code:

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

Generierte Schnittstelle

Klicken Sie auf die Schaltfläche Related Items (oder drücken Sie ⌃1) und wählen Sie dann Generated Interface aus , um die Swift-Oberfläche anzuzeigen, die aus einem Objective-C-Header generiert wird.

Geben Sie einen Überbrückungsheader für swiftc an

Das -import-objc-header gibt einen Header für den Import von swiftc an:

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

Verwenden Sie eine Modulzuordnung, um C-Header zu importieren

Ein Modul Karte kann einfach import mymodule durch die Konfiguration C - Header - Dateien zu lesen und sie als Swift - Funktionen erscheinen zu lassen .

module.modulemap eine Datei mit dem Namen module.modulemap in ein Verzeichnis mit dem Namen mymodule :

Verzeichnisaufbau

In der Modul-Map-Datei:

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

Dann import das Modul:

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

Verwenden Sie das Flag -I directory , um swiftc mitzuteilen, wo das Modul zu finden ist:

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

Weitere Informationen zur Modulzuordnungssyntax finden Sie in der Clang-Dokumentation zu Modulzuordnungen .

Feinkörniges Zusammenspiel zwischen Objective-C und Swift

Wenn eine API mit NS_REFINED_FOR_SWIFT markiert NS_REFINED_FOR_SWIFT , werden beim Import nach Swift zwei Unterstriche ( __ ) vorangestellt:

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

Die generierte Schnittstelle sieht folgendermaßen aus:

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

Jetzt können Sie die API durch eine weitere "Swifty" -Erweiterung ersetzen . In diesem Fall können wir einen optionalen Rückgabewert verwenden, um NSNotFound herauszufiltern :

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 den meisten Fällen möchten Sie möglicherweise einschränken, ob ein Argument für eine Objective-C-Funktion gleich nil . Dies geschieht mit _Nonnull Schlüsselwort _Nonnull , das jeden Zeiger oder Blockverweis qualifiziert:

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

Wenn das geschrieben ist, gibt der Compiler einen Fehler aus, wenn wir versuchen, aus unserem Swift-Code nil an diese Funktion zu übergeben:

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

Das Gegenteil von _Nonnull ist _Nullable , was bedeutet, dass es zulässig ist, nil in diesem Argument zu übergeben. _Nullable ist auch die Standardeinstellung. Durch die explizite Angabe von Code wird jedoch mehr selbstdokumentierter und zukunftssicherer Code ermöglicht.

Um den Compiler bei der Optimierung Ihres Codes weiter zu unterstützen, möchten Sie möglicherweise auch angeben, ob der Block escapet:

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

Mit diesem Attribut versprechen wir, die Bausteinreferenz nicht zu speichern und den Baustein nicht aufzurufen, nachdem die Funktion die Ausführung abgeschlossen hat.

Verwenden Sie die C-Standardbibliothek

Mit der C-Interoperabilität von Swift können Sie Funktionen und Typen aus der C-Standardbibliothek verwenden.

Unter Linux wird die C-Standardbibliothek über das Glibc Modul Glibc . auf Apple-Plattformen heißt es 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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow