Gérer les pointeurs tels que UnsafePointer <T> dans Swift

Cet article est l'article du 12ème jour du Swift Advent Calendar 2014.

Le calendrier de l'Avent approche à grands pas. Décembre est déjà le 12, ce qui vous fait sentir la fin de l'année.

Personnellement, en vieillissant, je sens que l'année est très tôt. L'ancêtre a également laissé les mots ** «Le nombre de jours vécus dans une année est le contraire de l'âge» **. (Ne faisons pas d'erreur que la valeur ne change pas tellement même si le nombre inverse de 1 ou plus est pris)


Passons maintenant au sujet de Swift.

La conception du langage pour Swift est bonne, mais la prise en charge de Xcode et du compilateur est toujours si élevée que je n'ai pas été motivé pour créer une application par moi-même. (Si vous optimisez un certain code, il peut boucler indéfiniment)

Cette fois, il ne s'agit pas du compilateur, mais d'accéder directement à la mémoire à l'aide de pointeurs.

Utiliser des pointeurs dans Swift

Compatibilité Swift avec le langage C

Tout d'abord, Swift dispose d'une API compatible avec le langage C.

Par exemple, lors de la création d'une application iOS ou Mac

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

Vous devriez vous souvenir d'avoir écrit. (Situé dans le modèle CoreData du projet)

L'adresse de la variable déclarée dans ce NSError? Est passée à l'argument de performFetch.

Si vous allez voir la définition de performFetch

func performFetch(error: NSErrorPointer) -> Bool

Et NSErrorPointer est aliasé comme ci-dessous.

typealias NSErrorPointer = AutoreleasingUnsafeMutablePointer<NSError?>

Le ʻAutoreleasingUnsafeMutablePointer `ici fonctionne comme un pointeur de langage C.

ʻUnsafe Pointer ʻetc.

Par nature, Swift n'a pas d'accès direct à la mémoire.

Cependant, c'est possible en utilisant ʻUnsafePointer `etc. dans l'API compatible avec le langage C mentionné ci-dessus.

J'ai mentionné ʻUnsafe Pointer `** etc. ** de plus tôt, mais il existe d'autres types dans la référence officielle.


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>

Comme mentionné ci-dessus, les types de pointeurs sont

Il est divisé en.

comme une fonctionnalité

--Swift utilise nil pour représenter NULL en langage C --Converti en ʻUnsafePointer `si nécessaire

À propos de la mise en œuvre

Utilisons-les réellement.

Cette fois, à titre d'exemple de pointeur, nous allons créer une fonction swapByPointer et l'introduire. (La fonction d'échange apparaît fréquemment dans l'exemple du pointeur.)

Je veux que le type soit de n'importe quel type, donc j'utilise des génériques.

** fonction swapByPointer **

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

appel

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

Ça ressemble à ça.

Nous définissons une fonction de swap normale et passons l'adresse comme argument. Nous affectons directement à la mémoire pointée par l'adresse dans la fonction.

In-Out (bonus)

Je pense qu'il y a un tsukkomi de "Non, n'est-il pas plus simple d'utiliser un tel ʻinout`?"

Cette fois, je veux utiliser ** pointer ** explicitement, donc je n'utilise pas ʻinout`.

Si vous demandez "Qu'est-ce que ʻinout`?", Veuillez lire le code ci-dessous.

** fonction swapByInout (version inout) **

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

appel

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

Gestion de la mémoire

La référence précédente provenait de l'adresse de la variable déjà réservée, mais si vous êtes familier avec le langage C, ce sera "** memory alloc **!?".

Bien sûr, il y en a.

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)

En guise de commentaire, j'ai également noté la situation en langage C.

Il y a trois codes qui nécessitent une explication: ʻalloc, dealloc et memory`.

var p = UnsafeMutablePointer.alloc(num)

En langage C

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

Ce sera.

Spécifiez le nombre de types déclarés dans num pour garantir la taille de mémoire requise.

p.dealloc(num)

En langage C

free(p);

Je le publie.

p.memory

En langage C

*p

est. Utilisé pour faire référence à la valeur de l'adresse.


Généralement, si vous connaissez ce degré, vous pouvez construire Swift avec l'idée du langage C.

en conclusion

J'ai donné ce code à Gist, alors veuillez vous y référer si vous le souhaitez.

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

De plus, si vous parlez de pointeurs, vous devriez vous demander ** "Qu'est-ce qu'un pointeur de fonction?" **.

Bien sûr, il existe également une API compatible pour travailler avec des pointeurs de fonction. Disons que quelqu'un veut le savoir ou l'introduira lorsque le ** numéro de stock de cet article atteint environ 100 **.

C'était une si bonne affaire pour quiconque, mais je ne pense pas qu'il y ait un article en japonais traitant des pointeurs dans Swift, alors veuillez le toucher si vous le souhaitez.

Recommended Posts

Gérer les pointeurs tels que UnsafePointer <T> dans Swift
Manipulez bien le caractère C ** avec Swift
Obtenez des informations contextuelles telles que HttpServletRequest dans Jersey
Traitez les fonctions et fermetures Swift comme des pointeurs de fonction en langage C