ios - tutorial - xcode




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

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

https://github.com/seivan/ScalarArithmetic

À partir de la version bêta 5, voici une liste de choses que vous ne pouvez actuellement pas faire avec Swan Swift https://github.com/seivan/ScalarArithmetic#sample

Je suggère d'exécuter la suite de tests avec et sans ScalarArithmetic uniquement pour voir ce qui se passe.

Je trouve les calculs Swift particulièrement maladroits lorsque, comme cela se produit souvent dans la vie réelle, je dois communiquer avec Cocoa Touch en ce qui concerne CGRect et CGPoint (par exemple, parce que nous parlons du frame ou des bounds de quelque chose).

CGFloat vs. Double

Considérez le code innocent suivant d'une sous-classe UIViewController:

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

La compilation de ce code échoue, avec l'erreur mystérieuse habituelle sur la dernière ligne:

Impossible de trouver une surcharge pour '*' qui accepte les arguments fournis

Comme vous le savez sans doute maintenant, cette erreur indique une sorte de décalage d’impédance entre les types. r.size.width arrive sous la forme d'une CGFloat, qui s'échange automatiquement avec un Swift Float mais ne peut pas interagir avec une variable Swift Double (qui, par défaut, correspond à quelle scale ).

L'exemple est artificiellement bref. Il existe donc une solution artificiellement simple, qui consiste à lancer l' scale à un flotteur dès le départ. Mais lorsque de nombreuses variables provenant de partout sont impliquées dans le calcul des éléments d'un CGRect proposé, il y a beaucoup d'incantation à faire.

Initialiseur Verbose

Une autre irritation est ce qui se produit lorsque le moment est venu de créer un nouveau CGRect. Malgré la documentation, il n'y a pas d'initialiseur avec des valeurs mais sans étiquettes. 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 nous lançons un Float, nous ne compilons pas:

Étiquettes d'argument manquantes 'x: y: width: height:' dans l'appel

Nous nous retrouvons donc sur CGRectMake , ce qui n’apporte aucune amélioration par rapport à Objective-C. Et parfois, CGRectMake et CGSizeMake n'apportent aucune amélioration. Considérez ce code de l'une de mes applications:

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

Dans un de mes projets, ça marche. Dans un autre, il échoue mystérieusement - le même code exact! - avec cette erreur:

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

C'est comme si, parfois, Swift essayait de "traverser le pont" en lançant un Float vers un NSNumber, ce qui est bien sûr la mauvaise chose à faire lorsque ce qui se trouve de l'autre côté du pont attend un CGFloat. Je n'ai pas encore compris quelle est la différence entre les deux projets qui provoquent l'erreur dans l'un mais pas dans l'autre (peut-être quelqu'un d'autre l'a fait).

REMARQUE: j'ai peut-être compris ce problème: il semble dépendre du paramètre de construction Build Active Architecture Only, ce qui suggère à son tour qu'il s'agit d'un problème 64 bits. Ce qui est logique, car Float ne serait pas compatible avec CGFloat sur un périphérique 64 bits. Cela signifie que le problème de déséquilibre impédance est encore pire que je ne le pensais.

Conclusion

Je cherche des mots pratiques de sagesse sur ce sujet. Je pense que quelqu'un a peut-être conçu une extension CGRect et CGPoint qui facilitera grandement la vie. (Ou peut-être quelqu'un a-t-il écrit une surcharge de fonctions d'arithmétiques supplémentaires, telles que la combinaison de CGFloat avec Int ou Double "ne fait que" fonctionner - si cela est possible.)


J'ai créé une extension pour Double et Int qui leur ajoute une propriété calculée CGFloatValue.

extension Double {
    var CGFloatValue: CGFloat {
        get {
            return CGFloat(self)
        }
    }
}
extension Int {
    var CGFloatValue: CGFloat {
        get {
            return CGFloat(self)
        }
    }
}

Vous y let someCGFloat = someDoubleOrInt.CGFloatValue en utilisant let someCGFloat = someDoubleOrInt.CGFloatValue

En outre, comme pour votre initialiseur CGRect, vous obtenez l'erreur d'étiquettes d'argument manquante car vous avez CGRect(x: d, y: d, width: d, height: d) les étiquettes, vous avez besoin de CGRect(x: d, y: d, width: d, height: d) Vous ne pouvez pas laisser les étiquettes. out sauf s'il n'y a qu'un seul argument.





swift