Behandeln Sie Zeiger wie UnsafePointer <T> in Swift

Dieser Artikel ist der Artikel zum 12. Tag von Swift Advent Calendar 2014.

Der Adventskalender ist gleich um die Ecke. Der Dezember ist bereits der 12., wodurch Sie das Ende des Jahres spüren.

Persönlich habe ich mit zunehmendem Alter das Gefühl, dass das Jahr sehr früh ist. Der Vorfahr hinterließ auch die Worte ** "Die Anzahl der Tage in einem Jahr ist das Gegenteil des Alters" **. (Machen wir keinen Fehler, dass sich der Wert nicht so stark ändert, selbst wenn die inverse Zahl 1 oder mehr verwendet wird.)


Kommen wir nun zum Thema Swift.

Das Sprachdesign für Swift ist gut, aber die Unterstützung für Xcode und den Compiler ist immer noch so hoch, dass ich nie motiviert war, selbst eine App zu erstellen. (Wenn Sie einen bestimmten Code optimieren, kann es zu einer Endlosschleife kommen.)

Diesmal geht es nicht um den Compiler, sondern darum, mit Zeigern direkt auf den Speicher zuzugreifen.

Verwenden Sie Zeiger in Swift

Schnelle Kompatibilität mit der Sprache C.

Erstens hat Swift eine API, die mit der C-Sprache kompatibel ist.

Zum Beispiel beim Erstellen einer iOS- oder Mac-Anwendung

var error: NSError? = nil
if !_fetchedResultsController!.performFetch(&error) {
     println("Unresolved error \(error), \(error?.localizedDescription)")
}
return _fetchedResultsController!

Sie sollten sich daran erinnern, geschrieben zu haben. (Befindet sich in der CoreData-Vorlage des Projekts)

Die Adresse der in diesem NSError deklarierten Variablen wird an das Argument performFetch übergeben.

Wenn Sie die Definition von "performFetch" sehen

func performFetch(error: NSErrorPointer) -> Bool

Und NSErrorPointer ist wie folgt aliasiert.

typealias NSErrorPointer = AutoreleasingUnsafeMutablePointer<NSError?>

Der AutoreleasingUnsafeMutablePointer funktioniert hier als C-Sprachzeiger.

UnsafePointer <T> usw.

Swift hat von Natur aus keinen direkten Zugriff auf den Speicher.

Es ist jedoch möglich, "UnsafePointer " usw. in der API zu verwenden, die mit der oben genannten C-Sprache kompatibel ist.

Ich habe UnsafePointer <T> ** etc. ** von früher erwähnt, aber es gibt andere Typen in der offiziellen Referenz.


For return types, variables, and arguments, the following mappings apply:

C Syntax Swift Syntax
const Type * UnsafePointer<Type>
Type * UnsafeMutablePointer<Type>

For class types, the following mappings apply:

C Syntax Swift Syntax
Type * const * UnsafePointer<Type>
Type * __strong * UnsafeMutablePointer<Type>
Type ** AutoreleasingUnsafeMutablePointer<Type>

Wie oben erwähnt, sind die Arten von Zeigern

Es ist unterteilt in.

als Merkmal

--Swift verwendet "nil", um "NULL" in C-Sprache darzustellen

Über die Implementierung

Lassen Sie uns diese tatsächlich verwenden.

Dieses Mal werde ich als Beispiel für einen Zeiger eine swapByPointer-Funktion einführen. (Die Swap-Funktion wird im Zeigerbeispiel häufig angezeigt.)

Ich möchte, dass der Typ ein beliebiger Typ ist, daher verwende ich Generika.

** swapByPointer Funktion **

func swapByPointer<T>(x: UnsafeMutablePointer<T>, y: UnsafeMutablePointer<T>) {
    let z: T = x.memory
    x.memory = y.memory
    y.memory = z
}

Anruf

var a: Int = 10
var b: Int = 20

// a = 10, b = 20
println("a = \(a), b = \(b)")

// Swap
swapByPointer(&a, &b)

// a = 20, b = 10
println("a = \(a), b = \(b)")

Es sieht aus wie das.

Ich habe eine normale Swap-Funktion definiert und die Adresse als Argument übergeben. Der Speicher, auf den die Adresse zeigt, wird direkt in der Funktion zugewiesen.

In-Out (Bonus)

Ich denke, es gibt einen Tsukkomi, der sagt: "Nein, ist es nicht einfacher, solch ein" Inout "zu verwenden?"

Dieses Mal möchte ich ** Zeiger ** explizit verwenden, daher verwende ich nicht inout.

Wenn Sie fragen "Was ist" inout "?", Lesen Sie bitte den folgenden Code.

** swapByInout-Funktion (Inout-Version) **

func swapByInout<T>(inout x: T, inout y: T) {
    let z: T = x
    x = y
    y = z
}

Anruf

var a: Int = 10
var b: Int = 20

// a = 10, b = 20
println("a = \(a), b = \(b)")

// Swap
swapByInout(&a, &b)

// a = 20, b = 10
println("a = \(a), b = \(b)")

Speicherverwaltung

Die vorherige Referenz stammt von der Adresse der bereits reservierten Variablen. Wenn Sie jedoch mit der Sprache C vertraut sind, lautet sie "** Speicherzuweisung ** !?".

Natürlich gibt es.

alloc

// Use UnsafeMutablePointer<T>
typealias IntPointer = UnsafeMutablePointer<Int>
// C Language:
//  typedef int *IntPointer;

var a_ptr = IntPointer.alloc(1)
// C Language:
//  int *a_ptr = (int *)malloc(1 * sizeof(int));
//  IntPointer a_ptr = (IntPointer)malloc(1 * sizeof(int));
//   or
//  int *a_ptr = (int *)calloc(1, sizeof(int));
var b_ptr = IntPointer.alloc(1)

a_ptr.memory = a
// C Language:
//  *a_ptr = a;
b_ptr.memory = b

// a_ptr.memory = 10, b_ptr.memory = 20
println("a_ptr.memory = \(a_ptr.memory), b_ptr.memory = \(b_ptr.memory)")

// Swap
swapByPointer(a_ptr, b_ptr)

// a_ptr.memory = 20, b_ptr.memory = 10
println("a_ptr.memory = \(a_ptr.memory), b_ptr.memory = \(b_ptr.memory)")

// Destroy
a_ptr.dealloc(1)
// C Language:
//  free(a_ptr);
b_ptr.dealloc(1)

Als Kommentar habe ich auch die Situation in C-Sprache niedergeschrieben.

Es gibt drei Codes, die einer Erklärung bedürfen: "alloc", "dealloc" und "memory".

var p = UnsafeMutablePointer.alloc(num)

In C-Sprache

Type *p = (Type *)malloc(num * sizeof(Type));
// or
Type *p = (Type *)calloc(num, sizeof(Type));

Es wird sein.

Geben Sie die Anzahl der deklarierten Typen in "num" an, um die erforderliche Speichergröße zu sichern.

p.dealloc(num)

In C-Sprache

free(p);

Ich gebe es frei.

p.memory

In C-Sprache

*p

ist. Wird verwendet, um auf den Wert in der Adresse zu verweisen.


Wenn Sie diesen Abschluss kennen, können Sie Swift im Allgemeinen mit der Idee der C-Sprache erstellen.

abschließend

Ich habe diesen Code an Gist weitergegeben. Bitte beziehen Sie sich darauf, wenn Sie möchten.

https://gist.github.com/kaneshin/564fc0780e0d1c9cac7d

Wenn Sie über Zeiger sprechen, sollten Sie auch gefragt werden ** "Was ist ein Funktionszeiger?" **.

Natürlich gibt es auch eine kompatible API für die Arbeit mit Funktionszeigern. Nehmen wir an, jemand möchte es wissen oder wird es vorstellen, wenn die ** Bestandsnummer dieses Artikels ungefähr 100 ** erreicht.

Es war so viel für jeden, aber ich glaube nicht, dass es einen Artikel auf Japanisch gibt, der sich mit Zeigern in Swift befasst. Bitte berühren Sie ihn, wenn Sie möchten.

Recommended Posts

Behandeln Sie Zeiger wie UnsafePointer <T> in Swift
Behandle C char ** gut mit Swift
Erhalten Sie Kontextinformationen wie HttpServletRequest in Jersey
Behandeln Sie Swift-Funktionen und -Verschlüsse als Zeiger für C-Sprachfunktionen