Swift Language
Lavorare con C e Objective-C
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).
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:
Per crearne uno manualmente, modifica l'impostazione di costruzione dell'intestazione di Bridging Objective-C :
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
:
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