UnsafePointer e UnsafeMutablePointer
Leggi e scrivi con attenzione nella memoria grezza.
UnsafePointer e UnsafeMutablePointer è una lezione Swift Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Swift Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Swift Academy include 4 lezioni in totale.
Puntatori tipizzati in Swift
I riferimenti sicuri di Swift non espongono mai gli indirizzi grezzi, ma quando interopera con C o costruisce strutture dati a basso livello può utilizzare puntatori tipizzati: UnsafePointer<T> per l'accesso in sola lettura e UnsafeMutablePointer<T> per la lettura e la scrittura.
Un puntatore tipizzato conosce il tipo dell'elemento, quindi può calcolare gli stride e leggere un valore con il tipo corretto.
// A pointer to an Int we can read but not write
func readFirst(_ p: UnsafePointer<Int>) -> Int {
return p.pointee
}La proprietà pointee
pointee è il valore a cui punta attualmente il puntatore. Con un puntatore mutabile può sia leggerlo sia assegnargli un valore; con un puntatore in sola lettura può soltanto leggerlo.
Accedere a pointee su memoria non inizializzata o deallocata produce comportamento non definito: il sistema dei tipi non lo rileverà.
let p = UnsafeMutablePointer<Int>.allocate(capacity: 1)
p.initialize(to: 42)
print(p.pointee) // 42
p.pointee = 99
print(p.pointee) // 99Allocare memoria
UnsafeMutablePointer<T>.allocate(capacity:) riserva spazio per capacity elementi, ma non li inizializza. La memoria è grezza e leggerla prima dell'inizializzazione è illegale.
// Reserve space for 3 Doubles (uninitialized)
let buffer = UnsafeMutablePointer<Double>.allocate(capacity: 3)
// Must initialize before reading any elementInizializzare e deinizializzare
Prima di leggere deve usare initialize. Prima di deallocare tipi che richiedono operazioni di pulizia, come classi o stringhe, deve usare deinitialize per rilasciare le relative risorse.
Il ciclo di vita è: 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()Abbini sempre allocate a deallocate
Ogni allocate deve essere associato esattamente a un deallocate, altrimenti si verifica una perdita di memoria. Usare defer subito dopo l'allocazione è il pattern più sicuro, perché viene eseguito indipendentemente dal modo in cui la funzione termina.
func process() {
let p = UnsafeMutablePointer<Int>.allocate(capacity: 1)
defer { p.deallocate() }
p.initialize(to: 7)
print(p.pointee)
} // deallocate runs here automaticallyAritmetica dei puntatori
I puntatori tipizzati supportano l'indicizzazione e l'aritmetica in unità di elemento, non in byte. p + 2 avanza di due stride di T. p[i] è una forma abbreviata di (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()Inizializzare più elementi
Per un blocco di memoria, initialize(repeating:count:) imposta ogni posizione sullo stesso valore, mentre initialize(from:count:) copia i valori da un altro buffer. Entrambi inizializzano completamente l'intervallo, rendendone sicura la lettura.
let dst = UnsafeMutablePointer<Int>.allocate(capacity: 4)
dst.initialize(repeating: 5, count: 4)
print(dst[3]) // 5
dst.deinitialize(count: 4)
dst.deallocate()Sola lettura e mutabilità
Una funzione che si limita a esaminare i dati dovrebbe accettare UnsafePointer<T>; una funzione che li modifica dovrebbe accettare UnsafeMutablePointer<T>. Un puntatore mutabile viene convertito implicitamente in uno di sola lettura, ma non è possibile il contrario: questo impone l'intento al confine dell'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 per le variabili locali
Per ottenere un puntatore temporaneo a un valore esistente senza allocare memoria, utilizzi withUnsafePointer(to:) o la sua forma mutabile. Il puntatore è valido solo all'interno della closure: non lo lasci mai sfuggire.
var value = 100
withUnsafeMutablePointer(to: &value) { ptr in
ptr.pointee += 1
}
print(value) // 101Errori comuni
I puntatori tipizzati sono potenti, ma non tollerano errori:
- Leggere
pointeeprima diinitializeproduce un comportamento non definito. - Dimenticare
deinitializeper i tipi che contengono risorse provoca perdite. - Lasciare sfuggire un puntatore di
withUnsafePointercrea un puntatore sospeso.
Qui il compilatore si fida di Lei: non esistono protezioni a runtime.
// DANGEROUS — pointer escapes the closure
// var escaped: UnsafePointer<Int>?
// withUnsafePointer(to: &x) { escaped = $0 }
// escaped!.pointee // dangling, undefined behaviorUna piccola pila manuale
Riunendo tutti i concetti: allochi un blocco, lo tratti come un insieme di elementi tramite l'indicizzazione e infine lo liberi. Questa è la base delle raccolte personalizzate e dell'interoperabilità con 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()Verifica rapida
Richiami il corretto ciclo di vita dei puntatori.
Riepilogo
Ora conosce i puntatori tipizzati:
UnsafePointerlegge, mentreUnsafeMutablePointerlegge e scrive.pointeeaccede al valore; l'aritmetica usa le unità di elemento.- Il ciclo di vita è allocate → initialize → use → deinitialize → deallocate, idealmente protetto con
defer.
Successivamente vedrà come i puntatori a buffer racchiudono un'intera area contigua in un'API compatibile con Collection.
Domande Frequenti
La lezione «UnsafePointer e UnsafeMutablePointer» è gratuita?
Sì — il testo completo di «UnsafePointer e UnsafeMutablePointer» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Swift Academy, passa a CoddyKit PRO. Il corso Swift Academy include 4 lezioni in totale.
Cosa imparerò in «UnsafePointer e UnsafeMutablePointer»?
Leggi e scrivi con attenzione nella memoria grezza. Eserciti Swift Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Swift Academy?
Non è richiesta alcuna esperienza precedente. Swift Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «UnsafePointer e UnsafeMutablePointer»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Swift Academy?
Sì. Ogni lezione Swift Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- MemoryLayout e allineamento
- UnsafePointer e UnsafeMutablePointer
- Puntatori buffer non sicuri
- withUnsafeBytes e interoperabilità con C