0Pricing
Swift Academy · Lezione

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

Allocare 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 element

Inizializzare 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 automatically

Aritmetica 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 directly

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

Errori comuni

I puntatori tipizzati sono potenti, ma non tollerano errori:

  • Leggere pointee prima di initialize produce un comportamento non definito.
  • Dimenticare deinitialize per i tipi che contengono risorse provoca perdite.
  • Lasciare sfuggire un puntatore di withUnsafePointer crea 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 behavior

Una 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:

  • UnsafePointer legge, mentre UnsafeMutablePointer legge e scrive.
  • pointee accede 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

  1. MemoryLayout e allineamento
  2. UnsafePointer e UnsafeMutablePointer
  3. Puntatori buffer non sicuri
  4. withUnsafeBytes e interoperabilità con C
← Torna a Swift Academy