UnsafePointer et UnsafeMutablePointer
Lisez et écrivez soigneusement dans la mémoire brute.
UnsafePointer et UnsafeMutablePointer est une leçon Swift Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Swift Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Swift Academy comprend 4 leçons au total.
Pointeurs typés en Swift
Les références sûres de Swift n'exposent jamais les adresses brutes, mais lorsque vous interagissez avec C ou construisez des structures de données de bas niveau, vous utilisez des pointeurs typés : UnsafePointer<T> pour un accès en lecture seule et UnsafeMutablePointer<T> pour la lecture et l'écriture.
Un pointeur typé connaît le type de l'élément. Il peut donc calculer les pas et lire une valeur correctement typée.
// A pointer to an Int we can read but not write
func readFirst(_ p: UnsafePointer<Int>) -> Int {
return p.pointee
}La propriété pointee
pointee est la valeur vers laquelle le pointeur pointe actuellement. Avec un pointeur mutable, vous pouvez la lire et lui attribuer une valeur ; avec un pointeur en lecture seule, vous pouvez uniquement la lire.
Accéder à pointee dans une mémoire non initialisée ou désallouée produit un comportement indéfini — le système de types ne le détectera pas.
let p = UnsafeMutablePointer<Int>.allocate(capacity: 1)
p.initialize(to: 42)
print(p.pointee) // 42
p.pointee = 99
print(p.pointee) // 99Allouer de la mémoire
UnsafeMutablePointer<T>.allocate(capacity:) réserve de l'espace pour capacity éléments, mais ne les initialise pas. La mémoire est brute et sa lecture avant initialisation est interdite.
// Reserve space for 3 Doubles (uninitialized)
let buffer = UnsafeMutablePointer<Double>.allocate(capacity: 3)
// Must initialize before reading any elementInitialiser et désinitialiser
Avant toute lecture, vous devez utiliser initialize. Avant de désallouer des types nécessitant un nettoyage, comme les classes ou les chaînes de caractères, vous devez utiliser deinitialize pour libérer leurs ressources.
Le cycle de vie est le suivant : allocate → initialize → use → deinitialize → deallocate.
let p = UnsafeMutablePointer<String>.allocate(capacity: 1)
p.initialize(to: "hello")
print(p.pointee)
p.deinitialize(count: 1) // releases the String
p.deallocate()Toujours associer allocate à deallocate
Chaque allocate doit correspondre exactement à un deallocate, sinon vous provoquez une fuite de mémoire. Utiliser le mécanisme de report immédiatement après l'allocation est le modèle le plus sûr, car il s'exécute quelle que soit la manière dont la fonction se termine.
func process() {
let p = UnsafeMutablePointer<Int>.allocate(capacity: 1)
defer { p.deallocate() }
p.initialize(to: 7)
print(p.pointee)
} // deallocate runs here automaticallyArithmétique des pointeurs
Les pointeurs typés prennent en charge l'indexation et l'arithmétique en unités d'éléments, et non en octets. p + 2 avance de deux pas de T. p[i] est un raccourci pour (p + i).pointee.
let p = UnsafeMutablePointer<Int>.allocate(capacity: 3)
p.initialize(repeating: 0, count: 3)
p[0] = 10
p[1] = 20
p[2] = 30
print((p + 1).pointee) // 20
p.deinitialize(count: 3)
p.deallocate()Initialiser plusieurs éléments
Pour un bloc de mémoire, initialize(repeating:count:) affecte la même valeur à chaque emplacement, tandis que initialize(from:count:) copie les données depuis un autre tampon. Les deux initialisent entièrement la plage, qui peut donc être lue en toute sécurité.
let dst = UnsafeMutablePointer<Int>.allocate(capacity: 4)
dst.initialize(repeating: 5, count: 4)
print(dst[3]) // 5
dst.deinitialize(count: 4)
dst.deallocate()Lecture seule ou mutable
Une fonction qui examine uniquement les données doit accepter un UnsafePointer<T> ; une fonction qui les modifie doit accepter un UnsafeMutablePointer<T>. Un pointeur mutable se convertit implicitement en pointeur en lecture seule, mais pas l'inverse : cela impose l'intention à la limite de l'API.
func sum(_ p: UnsafePointer<Int>, _ n: Int) -> Int {
var total = 0
for i in 0..<n { total += p[i] }
return total
}
// A mutable pointer can be passed here directlywithUnsafePointer pour les variables locales
Pour obtenir un pointeur temporaire vers une valeur existante sans effectuer d'allocation, utilisez withUnsafePointer(to:) ou sa forme mutable. Le pointeur n'est valide qu'à l'intérieur de la fermeture : ne le laissez jamais s'échapper.
var value = 100
withUnsafeMutablePointer(to: &value) { ptr in
ptr.pointee += 1
}
print(value) // 101Pièges courants
Les pointeurs typés sont puissants, mais impitoyables :
- Lire
pointeeavantinitializeproduit un comportement indéfini. - Oublier
deinitializepour des types qui détiennent des ressources provoque des fuites. - Laisser un pointeur de
withUnsafePointers'échapper crée un pointeur pendant.
Le compilateur vous fait confiance ici : il n'existe aucun garde-fou à l'exécution.
// DANGEROUS — pointer escapes the closure
// var escaped: UnsafePointer<Int>?
// withUnsafePointer(to: &x) { escaped = $0 }
// escaped!.pointee // dangling, undefined behaviorUne petite pile manuelle
En réunissant ces notions, vous pouvez allouer un bloc, le traiter comme une suite d'éléments à l'aide de l'indexation, puis le nettoyer. C'est le fondement des collections personnalisées et de l'interopérabilité avec C.
let n = 3
let stack = UnsafeMutablePointer<Int>.allocate(capacity: n)
stack.initialize(repeating: 0, count: n)
for i in 0..<n { stack[i] = i * i }
// stack now holds 0, 1, 4
stack.deinitialize(count: n)
stack.deallocate()Vérification rapide
Rappelez-vous le cycle de vie correct d'un pointeur.
Récapitulatif
Vous connaissez maintenant les pointeurs typés :
UnsafePointerlit les données ;UnsafeMutablePointerles lit et les écrit.pointeeaccède à la valeur ; l'arithmétique se fait en unités d'éléments.- Le cycle de vie est allocate → initialize → use → deinitialize → deallocate, idéalement protégé par
defer.
Vous verrez ensuite comment les pointeurs de buffer encapsulent toute une zone contiguë dans une API adaptée aux collections.
Questions Fréquemment Posées
La leçon « UnsafePointer et UnsafeMutablePointer » est-elle gratuite ?
Oui — le texte complet de « UnsafePointer et UnsafeMutablePointer » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Swift Academy, passe à CoddyKit PRO. Le cours Swift Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « UnsafePointer et UnsafeMutablePointer » ?
Lisez et écrivez soigneusement dans la mémoire brute. Tu pratiques Swift Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Swift Academy ?
Aucune expérience préalable n'est requise. Swift Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.
Combien de temps prend la leçon « UnsafePointer et UnsafeMutablePointer » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Swift Academy ?
Oui. Chaque leçon Swift Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- MemoryLayout et alignement
- UnsafePointer et UnsafeMutablePointer
- Pointeurs de tampons non sûrs
- withUnsafeBytes et interopérabilité C