0Pricing
Swift Academy · Lektion

UnsafePointer und UnsafeMutablePointer

Lesen und schreiben Sie vorsichtig im Rohspeicher.

UnsafePointer und UnsafeMutablePointer ist eine kostenlose Swift Academy-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Swift Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Swift Academy-Kurs umfasst insgesamt 4 Lektionen.

Typisierte Zeiger in Swift

Swifts sichere Referenzen legen niemals rohe Adressen offen. Bei der Zusammenarbeit mit C oder beim Erstellen von Datenstrukturen auf niedriger Ebene greifen Sie jedoch auf typisierte Zeiger zurück: UnsafePointer<T> für schreibgeschützten Zugriff und UnsafeMutablePointer<T> für Lese- und Schreibzugriff.

Ein typisierter Zeiger kennt den Elementtyp und kann daher Strides berechnen und einen korrekt typisierten Wert lesen.

// A pointer to an Int we can read but not write
func readFirst(_ p: UnsafePointer<Int>) -> Int {
    return p.pointee
}

Die pointee-Eigenschaft

pointee ist der Wert, auf den der Zeiger aktuell zeigt. Bei einem veränderbaren Zeiger können Sie ihn sowohl lesen als auch zuweisen; bei einem schreibgeschützten Zeiger können Sie ihn nur lesen.

Der Zugriff auf pointee in nicht initialisiertem oder freigegebenem Speicher führt zu undefiniertem Verhalten — das Typsystem erkennt dies nicht.

let p = UnsafeMutablePointer<Int>.allocate(capacity: 1)
p.initialize(to: 42)
print(p.pointee)   // 42
p.pointee = 99
print(p.pointee)   // 99

Speicher allokieren

UnsafeMutablePointer<T>.allocate(capacity:) reserviert Platz für capacity Elemente, initialisiert sie jedoch nicht. Der Speicher ist roh, und das Lesen vor der Initialisierung ist unzulässig.

// Reserve space for 3 Doubles (uninitialized)
let buffer = UnsafeMutablePointer<Double>.allocate(capacity: 3)
// Must initialize before reading any element

initialize und deinitialize

Vor dem Lesen müssen Sie initialize aufrufen. Bevor Sie Typen freigeben, die eine Bereinigung benötigen, etwa Klassen oder Strings, müssen Sie deinitialize aufrufen, um ihre Ressourcen freizugeben.

Der Lebenszyklus lautet: 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()

allocate immer mit deallocate paaren

Jedes allocate muss genau einem deallocate zugeordnet sein, andernfalls tritt ein Speicherleck auf. defer direkt nach der Allokation zu verwenden, ist das sicherste Muster, da es unabhängig davon ausgeführt wird, wie die Funktion endet.

func process() {
    let p = UnsafeMutablePointer<Int>.allocate(capacity: 1)
    defer { p.deallocate() }
    p.initialize(to: 7)
    print(p.pointee)
} // deallocate runs here automatically

Zeigerarithmetik

Typisierte Zeiger unterstützen Indizierung und Arithmetik in Elementeinheiten, nicht in Bytes. p + 2 rückt um zwei Strides von T vor. p[i] ist eine Kurzform für (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()

initialize für mehrere Elemente

Bei einem Speicherblock setzt initialize(repeating:count:) jede Position auf denselben Wert, während initialize(from:count:) Werte aus einem anderen Puffer kopiert. Beide initialisieren den Bereich vollständig, sodass er sicher gelesen werden kann.

let dst = UnsafeMutablePointer<Int>.allocate(capacity: 4)
dst.initialize(repeating: 5, count: 4)
print(dst[3]) // 5
dst.deinitialize(count: 4)
dst.deallocate()

Schreibgeschützt vs. veränderbar

Eine Funktion, die Daten nur untersucht, sollte UnsafePointer<T> verwenden; eine Funktion, die Daten verändert, verwendet UnsafeMutablePointer<T>. Ein veränderbarer Zeiger kann implizit in einen schreibgeschützten konvertiert werden, aber nicht umgekehrt — so wird die beabsichtigte Verwendung an der API-Grenze durchgesetzt.

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 für lokale Werte

Um einen temporären Zeiger auf einen vorhandenen Wert zu erhalten, ohne Speicher zu allokieren, verwenden Sie withUnsafePointer(to:) oder die veränderbare Variante. Der Zeiger ist nur innerhalb der Closure gültig — lassen Sie ihn niemals nach außen gelangen.

var value = 100
withUnsafeMutablePointer(to: &value) { ptr in
    ptr.pointee += 1
}
print(value) // 101

Häufige Fehler

Typisierte Zeiger sind mächtig, verzeihen aber keine Fehler:

  • Der Zugriff auf pointee vor initialize führt zu undefiniertem Verhalten.
  • Wenn Sie bei Typen, die Ressourcen enthalten, deinitialize vergessen, entstehen Speicherlecks.
  • Wenn ein Zeiger aus withUnsafePointer nach außen gelangt, entsteht ein Dangling Pointer.

Der Compiler vertraut Ihnen an dieser Stelle — es gibt keine Schutzvorkehrungen zur Laufzeit.

// DANGEROUS — pointer escapes the closure
// var escaped: UnsafePointer<Int>?
// withUnsafePointer(to: &x) { escaped = $0 }
// escaped!.pointee  // dangling, undefined behavior

Ein kleiner manueller Stack

Wenn Sie alles zusammenführen, allokieren Sie zunächst einen Block, behandeln ihn mithilfe der Indizierung als eine Folge von Elementen und räumen anschließend auf. Das ist die Grundlage eigener Collections und der C-Integration.

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()

Kurze Überprüfung

Rufen Sie sich den korrekten Lebenszyklus eines Zeigers ins Gedächtnis.

Zusammenfassung

Sie kennen nun typisierte Zeiger:

  • UnsafePointer liest, UnsafeMutablePointer liest und schreibt.
  • pointee greift auf den Wert zu; die Arithmetik erfolgt in Elementeinheiten.
  • Der Lebenszyklus lautet allocate → initialize → use → deinitialize → deallocate und sollte idealerweise mit defer abgesichert werden.

Als Nächstes sehen Sie, wie Buffer Pointers einen ganzen zusammenhängenden Bereich in eine Collection-freundliche API einbinden.

Häufig gestellte Fragen

Ist die Lektion „UnsafePointer und UnsafeMutablePointer“ kostenlos?

Ja — der vollständige Text von „UnsafePointer und UnsafeMutablePointer“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Swift Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Swift Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „UnsafePointer und UnsafeMutablePointer“?

Lesen und schreiben Sie vorsichtig im Rohspeicher. Du übst Swift Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Swift Academy zu starten?

Keine Vorkenntnisse erforderlich. Swift Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.

Wie lange dauert die Lektion „UnsafePointer und UnsafeMutablePointer“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Swift Academy-Lektion Code schreiben und ausführen?

Ja. Jede Swift Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. MemoryLayout und Ausrichtung
  2. UnsafePointer und UnsafeMutablePointer
  3. Unsichere Buffer-Pointer
  4. withUnsafeBytes und C-Interop
← Zurück zu Swift Academy