ssortingng.withCSsortingng et UnsafeMutablePointer (mutation: cssortingng) encapsulés dans une fonction

J’ai un problème avec Ssortingng.withCSsortingng {} associé à UnsafeMutablePointer (mutating: …).

Étant donné: une fonction C comme celle-ci

randomSign(xml_ssortingng: UnsafeMutablePointer!) -> Uint 

Aussi donné: une chaîne comme

 str = "some xml_tag" 

Mon code de travail est comme ça (VERSION_1)

 func randomSignWrapper_1(xml_tag_str: Ssortingng) -> Uint { let result = xml_str.withCSsortingng { s in return randomSign(UnsafeMutablePointer(mutating: s)) } return result } 

Mais je veux que le withCSsortingng soit placé dans une fonction séparée comme celle-ci:

 func testFunction(_ x: Ssortingng) -> UnsafeMutablePointer{ return x.withCSsortingng{s in return UnsafeMutablePointer(mutating: s) } } 

Pour que je puisse facilement le réutiliser (VERSION_2)

 func randomSignWrapper_2(xml_tag_str: Ssortingng) -> Uint { let result = randomSign(testFunction(xml_tag_str)) return result } 

Mais le problème est que VERSION_1 fournit la bonne valeur de retour, alors que VERSION_2 ne fonctionne pas correctement et me dit que les données sont erronées. Et j’aimerais savoir pourquoi il se comporte comme ça? Et comment le résoudre pour que je puisse l’utiliser de la manière décrite?

Vérifiez la référence de withCSsortingng(_:) .

Discussion

La méthode withCSsortingng (_ 🙂 garantit que la durée de vie de la séquence s’étend jusqu’à l’exécution du corps. L’argument pointeur du corps n’est valable que pour la durée de vie de la fermeture. N’échappez pas de la fermeture pour une utilisation ultérieure.

Votre code VERSION_2 tente de l’ échapper de la fermeture pour une utilisation ultérieure . Ce n’est pas une utilisation valide de withCSsortingng(_:) .

La région contenant la représentation UTF-8 de la Ssortingng est temporelle et Swift Runtime la publiera à tout moment.

Vous pouvez écrire quelque chose comme ceci:

 func utf8Array(from ssortingng: Ssortingng) -> [Int8] { return ssortingng.cSsortingng(using: .utf8)! } func randomSignWrapper_3(xml_tag_str: Ssortingng) -> UInt { var charArray = utf8Array(from: xml_tag_str) let result = randomSign(xml_ssortingng: &charArray) return result } 

Mais je me demande si vous devez définir une fonction telle que utf8Array(from:) .

withCSsortingng { ... } crée une représentation temporaire de la chaîne Swift en tant que séquence UTF-8 à withCSsortingng { ... } , qui est valide uniquement à l’intérieur de la fermeture. Passer le pointeur à l’extérieur de la fermeture est un comportement indéfini.

Notez également que vous ne pouvez pas transformer la chaîne en utilisant ce pointeur. Passer UnsafeMutablePointer(mutating: $0) ne fait que faire croire au compilateur que la mémoire pointée est modifiable, mais qu’il s’agit d’un comportement indéfini et qu’elle peut même planter.

Si la fonction randomSign() ne modifie pas la chaîne donnée, la meilleure solution consiste à modifier sa déclaration C en prenant une chaîne constante :

 unsigned long randomSign(const char *xml_ssortingng); 

Ce serait importé à Swift comme

 func randomSign(_ xml_ssortingng: UnsafePointer!) -> UInt 

Maintenant, vous pouvez passer une chaîne Swift directement à cette fonction:

 let str = "some xml_tag" let result = randomSign(str) 

Le compilateur insère automatiquement le code permettant de créer une représentation UTF-8 temporaire et de le transmettre à la fonction, compare la valeur de Ssortingng au comportement du paramètre de fonction UnsafePointer .

Si vous ne pouvez pas modifier la déclaration C, vous pouvez toujours l’appeler en tant que

 let str = "some xml_tag" let result = randomSign(UnsafeMutablePointer(mutating: str)) 

également sans avoir besoin de votre propre fonction d’assistance.

Mise à jour: La dernière suggestion n’est pas correcte. La chaîne temporaire créée par le compilateur est uniquement UnsafeMutablePointer() pendant l’appel de UnsafeMutablePointer() mais n’est pas nécessairement toujours valide lors de l’appel de randomSign() .