Comme nous le savons tous, CGFloat
(qui est omniprésent dans CoreGraphics, UIKit etc) peut être un 32 bits ou nombre à virgule flottante 64 bits, en fonction de l'architecture du processeur .Conversion entre CGFloat et NSNumber sans promotion inutile de doubler
En C, CGFloat
il est un typealias float
ou à double
, à Swift est-il défini comme un struct CGFloat
avec une propriété native
(qui est Float
ou Double
).
Il a été observé à plusieurs reprises qu'un NSNumber
peut être créé à partir et converti en Float
et Double
, mais qu'il n'y existe pas conversions similaires en provenance et à CGFloat
. Le conseil général (par exemple dans Convert CGFloat to NSNumber in Swift) est de converti par Double
CGFloat <--> Double <--> NSNumber
Exemple:
let c1 = CGFloat(12.3)
let num = NSNumber(double: Double(c1))
let c2 = CGFloat(num.doubleValue)
et qui est simple et correcte, aucune précision est perdue. De nos jours, la plupart des plateformes sont 64 bits, et la conversion CGFloat/Double
est triviale et probablement optimisée par le compilateur.
Cependant, il a suscité ma curiosité si une conversion peut se faire sans promotion CGFloat
-Double
sur les plates-formes 32 bits.
On pourrait utiliser une instruction de configuration de construction (comme par exemple dans Should conditional compilation be used to cope with difference in CGFloat on different architectures?):
extension NSNumber {
convenience init(cgFloatValue value : CGFloat) {
#if arch(x86_64) || arch(arm64)
self.init(double: value.native)
#else
self.init(float: value.native)
#endif
}
}
Mais si Swift est porté sur d'autres architectures qui ne sont pas Intel ou ARM? Cela ne semble pas très à l'épreuve du futur.
On pourrait aussi utiliser la CGFLOAT_IS_DOUBLE
constante (comme par exemple dans NSNumber from CGFloat):
if CGFLOAT_IS_DOUBLE != 0 {
// ...
} else {
// ...
}
L'inconvénient est que le compilateur émet toujours un « ne sera jamais exécuté » avertissement sur l'un des les cas.
Donc, pour faire la longue histoire courte:
- Comment peut-on convertir entre
CGFloat
etNSNumber
de manière sûre, sans avertissement du compilateur, et sans promotion inutile deDouble
?
Veuillez noter qu'il s'agit d'un problème «académique». Comme mentionné ci-dessus (et dans d'autres Q & A) on peut simplement convertir via Double
pratiquement.
Je poste une "réponse personnelle" ici dans l'esprit de share your knowledge, Q&A-style. Bien sûr, d'autres réponses sont les bienvenues!
Il convient de noter que d'Avril 2017, avec Swift 3.1 publiée, la distribution entre NSNumber et CGFloat peut échouer à l'exécution et deviendra un casting coché dans Swift 4, donc la solution la plus compliquée pourrait être le chemin à parcourir. –