Swift Language
Travailler avec C et Objective-C
Recherche…
Remarques
Pour plus d'informations, consultez la documentation d'Apple sur l' utilisation de Swift avec Cocoa et Objective-C .
Utiliser les classes Swift du code Objective-C
Dans le même module
Dans un module nommé " MyModule ", Xcode génère un en-tête nommé MyModule-Swift.h
qui expose les classes Swift publiques à Objective-C. Importez cet en-tête pour utiliser les classes 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
Paramètres de construction pertinents:
- Nom de l'en-tête de l'interface générée par Objective-C : contrôle le nom de l'en-tête Obj-C généré.
- Installez Objective-C Compatibility Header : si l'en-tête -Swift.h doit être un en-tête public (pour les cibles du framework).
Dans un autre module
Utiliser @import MyFramework;
importe l'ensemble du module, y compris les interfaces Obj-C, aux classes Swift (si le paramètre de construction susmentionné est activé).
Utilisation de classes Objective-C à partir du code Swift
Si MyFramework contient des classes Objective-C dans ses en-têtes publiques (et dans l'en-tête parapluie), il import MyFramework
pour les utiliser depuis Swift.
Passerelles
Un en- tête de pontage rend les déclarations Objective-C et C supplémentaires visibles pour le code Swift. Lors de l'ajout de fichiers de projet, Xcode peut proposer de créer automatiquement un en-tête de pontage:
Pour en créer un manuellement, modifiez le paramètre de génération Objective-C Bridging Header :
A l'intérieur de l'en-tête de pontage, importez les fichiers nécessaires à l'utilisation du code:
// MyApp-Bridging-Header.h
#import "MyClass.h" // allows code in this module to use MyClass
Interface générée
Cliquez sur le bouton Éléments associés (ou appuyez sur ⌃1), puis sélectionnez Interface générée pour voir l'interface Swift générée à partir d'un en-tête Objective-C.
Spécifiez un en-tête de pontage pour swiftc
Le -import-objc-header
spécifie un en-tête pour swiftc
à importer:
// 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)
Utiliser une carte de module pour importer des en-têtes C
Une carte de module peut simplement import mymodule
en le configurant pour lire les fichiers d'en-tête C et les faire apparaître comme des fonctions Swift.
Placez un fichier nommé module.modulemap
dans un répertoire nommé mymodule
:
Dans le fichier de carte du module:
// mymodule/module.modulemap
module mymodule {
header "defs.h"
}
Puis import
le module:
// demo.swift
import mymodule
print("Empty color: \(Color())")
Utilisez l'indicateur de -I directory
pour indiquer à swiftc
où trouver le module:
swiftc -I . demo.swift # "-I ." means "search for modules in the current directory"
Pour plus d'informations sur la syntaxe de la carte de module, consultez la documentation de Clang sur les cartes de module .
Interaction fine entre Objective-C et Swift
Lorsqu'une API est marquée avec NS_REFINED_FOR_SWIFT
, elle sera préfixée par deux NS_REFINED_FOR_SWIFT
soulignement ( __
) lors de son importation dans Swift:
@interface MyClass : NSObject
- (NSInteger)indexOfObject:(id)obj NS_REFINED_FOR_SWIFT;
@end
L' interface générée ressemble à ceci:
public class MyClass : NSObject {
public func __indexOfObject(obj: AnyObject) -> Int
}
Vous pouvez maintenant remplacer l’API par une extension plus "Swifty". Dans ce cas, nous pouvons utiliser une valeur de retour facultative , en filtrant 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
}
Dans la plupart des cas , vous pouvez limiter ou non un argument à une fonction Objective-C pourrait être nil
. Ceci est fait en utilisant le mot clé _Nonnull
, qui qualifie tout pointeur ou référence de bloc:
void
doStuff(const void *const _Nonnull data, void (^_Nonnull completion)())
{
// complex asynchronous code
}
Avec cela écrit, le compilateur doit émettre une erreur chaque fois que nous essayons de passer nil
à cette fonction à partir de notre code Swift:
doStuff(
nil, // error: nil is not compatible with expected argument type 'UnsafeRawPointer'
nil) // error: nil is not compatible with expected argument type '() -> Void'
Le contraire de _Nonnull
est _Nullable
, ce qui signifie qu'il est acceptable de passer nil
dans cet argument. _Nullable
est aussi la valeur par défaut. Cependant, le spécifier explicitement permet un code plus auto-documenté et à l'épreuve du futur.
Pour aider le compilateur à optimiser votre code, vous pouvez également spécifier si le bloc est échappé:
void
callNow(__attribute__((noescape)) void (^_Nonnull f)())
{
// f is not stored anywhere
}
Avec cet attribut, nous promettons de ne pas enregistrer la référence de bloc et de ne pas appeler le bloc une fois l'exécution de la fonction terminée.
Utilisez la bibliothèque standard C
L'interopérabilité C de Swift vous permet d'utiliser des fonctions et des types de la bibliothèque standard C.
Sous Linux, la bibliothèque standard C est exposée via le module Glibc
; sur les plateformes Apple, cela s'appelle 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