60 votes

Numérique rapide et CGFloat (CGPoint, CGRect, etc.)

Je suis la recherche Swift numerics particulièrement maladroite lorsque, comme cela arrive souvent dans la vie réelle, j'ai pour communiquer avec Cocoa Touch à l'égard de CGRect et CGPoint (par exemple, parce que nous parlons de quelque chose de l' frame ou bounds).

CGFloat vs Double

Considérez les points suivants à l'air innocent de code à partir d'un UIViewController sous-classe:

let scale = 2.0
let r = self.view.bounds
var r2 = CGRect()
r2.size.width = r.size.width * scale

Ce code ne peut pas compiler, avec l'habituel mystérieux erreur sur la dernière ligne:

Ne pouvait pas trouver une surcharge pour les '*' qui accepte les arguments fournis

Cette erreur, je suis sûr que vous le savez maintenant, indique une sorte d'adaptation d'impédance entre les types. r.size.width arrive comme un CGFloat, qui va échanger automatiquement avec une Swift Float, mais ne peut pas interagir avec une Swift variable Double (qui, par défaut, est-ce que scale ).

L'exemple est artificiellement bref, il y a donc un artificiellement la solution la plus simple, qui consiste à jeter scale d'un Flotteur à partir de l'obtenir-aller. Mais lorsque le nombre de variables tirées de partout sont impliqués dans le calcul d'un projet de CGRect des éléments, il y a beaucoup de casting à faire.

Verbose Initialiseur

Un autre irritation est ce qui arrive quand vient le temps de créer un nouveau CGRect. En dépit de la documentation, il n'y a pas d'initialiseur avec des valeurs mais sans étiquette. Cela ne parvient pas à compiler, car nous avons des Doubles:

let d = 2.0
var r3 = CGRect(d, d, d, d)

Mais même si on jette d à un Flotteur, nous n'avons pas à compiler:

Argument manquant étiquettes 'x:y:largeur:hauteur:" en appel

Nous avons donc fini par tomber en arrière sur CGRectMake, ce qui n'est pas d'amélioration sur Objective-C. Et parfois CGRectMake et CGSizeMake sont pas d'amélioration. Considérer ce code réel de l'un de mes apps:

let kSEP : Float = 2.0
let intercellSpacing = CGSizeMake(kSEP, kSEP);

Dans un de mes projets, qui fonctionne. Dans l'autre, il échoue mystérieusement - exactement le même code! - avec cette erreur:

'NSNumber" n'est pas un sous-type de "CGFloat'

C'est comme si, parfois, Swift essaie de "traverser le pont" par coulée d'un Flotteur pour une NSNumber, ce qui bien sûr est la mauvaise chose à faire lorsque ce qui est de l'autre côté du pont, s'attend à un CGFloat. Je n'ai pas encore compris ce qu'est la différence entre les deux projets qui provoque l'erreur à apparaître dans l'un mais pas l'autre (peut-être quelqu'un d'autre).

NOTE: j'ai peut-être trouvé le problème: il semble dépendre de la construction Active Seulement l'Architecture paramètre de construction, qui à son tour suggère que c'est un 64 bits question. Ce qui est logique, puisque le Flotteur ne serait pas un match pour CGFloat sur un périphérique 64 bits. Cela signifie que la différence d'impédance problème est encore pire que je ne le pensais.

Conclusion

Je suis à la recherche pour la pratique des paroles de sagesse sur ce sujet. Je suis en train de penser que quelqu'un peut l'avoir conçu quelques CGRect et CGPoint extension qui va rendre la vie beaucoup plus facile. (Ou peut-être quelqu'un a écrit une cargaison supplémentaire opérateur arithmétique fonction des surcharges, telles que la combinaison de CGFloat de l'Int ou Double "fonctionne" - si c'est possible.)

24voto

BergQuester Points 3284

Tapant scale de CGFloat, comme vous l'avez découvert, est en effet la façon de gérer le problème de frappe rapide. De référence pour les autres:

let scale: CGFloat = 2.0
let r = self.view.bounds
var r2 = CGRect()
r2.size.width = r.width * scale

Vous ne savez pas comment répondre à votre deuxième question, vous pouvez poster séparément avec un titre différent.

Mise à jour:

Swift créateur et développeur en chef Chris Lattner avait ceci à dire sur cette question sur le Apple Developer Forum le 4 juillet 2014:

Ce qui se passe ici est que CGFloat est un typealias pour Flotteur ou Double selon que vous êtes en train de construire pour 32 ou 64 bits. C'est exactement de cette façon Objective-C fonctionne, mais c'est problématique dans Swift parce que Swift n'autorise pas les conversions implicites.

Nous sommes conscients de ce problème et d'envisager d'être sérieux: nous sommes à l'évaluation de plusieurs différentes solutions dès maintenant et va rouler dans un plus tard bêta. Comme vous remarquez, vous pouvez faire face à cela, aujourd'hui, par la conversion en Double. C'est inélégant, mais efficace :-)

Mise À Jour De Xcode 6 Beta 5:

Un CGFloat peut être construit à partir de tout type Entier (y compris le taille types d'entiers) et vice-versa. (17670817)

15voto

Seivan Points 146

J'ai écrit une bibliothèque qui gère la surcharge d'opérateur pour permettre l'interaction entre Int, CGFloat et Double.

https://github.com/seivan/ScalarArithmetic

Comme de la Bêta 5, voici une liste de choses que vous ne pouvez pas faire avec la vanille Swift. https://github.com/seivan/ScalarArithmetic#sample

Je vous conseille d'exécuter la suite de tests avec et sans ScalarArithmetic juste pour voir ce qu'il se passe.

6voto

Andrew97p Points 297

J’ai créé une extension pour Double et Int qui ajoute une propriété calculée de CGFloatValue à eux.

Vous accédez à elle en utilisant``

En outre, comme pour votre initialiseur CGRect, vous obtenez l’erreur d’étiquettes argument manquant parce que vous avez laissé les étiquettes, vous devez `` vous ne peut pas omettre les étiquettes à moins qu’il n’y a qu’un seul argument.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X