Type Decimal
Rocou
Membre
Avez-vous une astuce pour manipuler facilement des variables de type decimal?
Il y a tout de même beaucoup de fonctions ou d'objets qui ne connaissent pas ce type, ce qui implique de nombreuses conversions. Du coup, je me demande quels sont les avantages à utiliser le type decimal.
Mots clés:
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Pas de perte de précision, ça calcule en décimal et pas en binaire.
Je n'ai jamais travaillé avec Decimal, alors je connais mal.
En Swift, on peut toujours utiliser NSDecimalNumber qui est un NSNumber et utilisable par exemple dans un NSNumberFormatter.
J'ajouterai que théoriquement tu ne vas pas utiliser
Decimal
pour autre choses que des manipulations de valeurs entrées par l'utilisateur ou provenant d'un web service.Ce qui fait que normalement tu ne vas pas passer des
Decimal
à n'importe quelle function. Comme l'a dit @CéroceDecimal
est toll-free bridged versNSDecimalNumber
qui dérive deNSNumber
. Donc pour tout ce qui est de la question d'affichage des valeurs tu n'as pas à t'inquiéter non plus.NSControl
etNSNumberFormatter
aiment bienNSNumber
.Je serai tenté alors de suggérer que si tu es si ennuyé par des conversions intempestives c'est peut-être que tu utilise mal
Decimal
.Dis nous-en plus sur ces conversions.
C'est dans le cadre de ma petite application "Pourcentage calc":
1. l'utilisateur saisit des nombres,
2. ils sont récupérés sous forme de texte,
3. puis convertis en décimal,
4. les calculs se font
5. les résultats (au type decimal) sont convertis en texte
6. le texte est affiché
NumberFormatter
a une propriétégeneratesDecimalNumbers
qui te fournira unNSNumber
bridgeable versDecimal
. Comme suit :Après comme je t'ai dit si tu utilise les NSBindings c'est encore plus simple et automatique.
Le NumberFormatter gère automatiquement la localisation du symbole décimal ? Ou est-ce que l'exemple ne fonctionne qu'en dialecte British ?
Effectivement
NumberFormatter
gère la localisation. ToujoursLocale.current
par défaut. Chez moi c'est en_CA@currency=EUR pour des raisons diverses (j'avoue être étonné mais si c'est le cas c'est qu'il y a une raison, que j'ai oublié bien entendu...).C'est vrai qu'avec une locale fr_FR il faut plutôt écrire
J'ai essayé un truc comme ça:
let tauxInteret_dec = nf.number(from: tauxInteret_remb.stringValue) as? Decimal
Mais dans tauxInteret_dec j'ai "nil" alors que dans tauxInteret_remb.stringValue j'ai bien la valeur attendue.
Pour l'instant, je n'ai rien compris au Bindings. Je creuserai mais pour le moment, je fais l'impasse.
Il faut appliquer le formatter sur le
NSTextField
. AppKit se charge du reste pour toi:Note que comme la locale est "fr_FR" (ce qui doit être le cas sur ta machine) le séparateur décimal est la virgule.
Bien vérifier que la locale est "fr_FR" comme l'a dit Pyroh
Chez moi, j'ai "en_FR" je sais pas comment il est arrivé a faire ce mix !
C'est bien compliqué tout ceci
Ouais la conception d'applications c'est compliqué quand on creuse un peu. 😉
J'ai mis à jour mon exemple sur les bindings sur GitHub. Et j'ai rajouté un petit truc en plus pour toi.
Même pas vrai ! Il y a des cours sur Internet pour apprendre à créer des applications en 3 semaines ! 😓
T'as déjà entendu parler des crèmes amaigrissantes 😁 ?
@Pyroh un grand merci pour le "petit truc en plus pour moi"!
J'essaie de comprendre les liens entre le code et les objets du storyboard cependant je n'arrive pas à "connecter les "bindings". Le bouton "connect" est grisé, comme le montre la photo qui suit:
Mais de rien !
Oublie ça pour les bindings. De mémoire ça a fonctionné bizarrement il y a de ça bien des lunes mais ça ne fonctionne plus. Ou si ça fonctionne c'est pas intuitif. Joue la sécurité :
Note que l'architecture est inutilement compliquée on pourrait très bien fusionner
CalculusEngine
avecCalculusViewController
mais utiliser unNSObjectController
c'est plus propre et best-practice.Sinon pour rigoler j'ai répliqué cette partie en SwiftUI (release 3, macOS12 mini) :
Bon, je n'arrive pas à compiler.
J'ai repris un bout de ton code (celui concernant la fonction add() ), j'ai créé une vue, installé trois NSTextField et scrupuleusement repris tous tes réglages mais chez moi cela donne une erreur à la compilation:
libc++abi: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ valueForUndefinedKey:]: this class is not key value coding-compliant for the key totalBTC.'
terminating with uncaught exception of type NSException
"totalBTC", c'est un de mes TextField. Si tu as une idée de ce qui peut se passer, je suis preneur!
Ce n'est pas une erreur de runtime ça?
Y'a un truc qui croit être un de tes TextField, mais qui est en réalité un NSObject, et donc qui ne connait pas totalBTC.
Je n'arrive pas à voir où est le souci. Pourtant, il y a trois fois rien dans le code.
Il y a cependant des choses que je ne comprends pas que j'ai tout simplement recopiées. J'appréhende le truc peu à peu mais quand il y a un souci à la compilation, je n'avance plus du tout.
Alors ton code compile très bien rassure-toi. Si tu regarde le message d'erreur tu vois que c'est une exception qui est levée (il faut que le code compile et tourne pour ça).
Exception qui pour le coup t'informe du soucis : this class is not key value coding-compliant for the key totalBTC.
La réponse la plus simple à ton soucis est que tu as bound (bind au passé, j'aime pas "bindé") ton
NSTextField
à la propriététotalBTC
d'un objet. Lequel ne comportant malheureusement pas la propriété sus-nommée.Le binding fonctionne de cette manière: tu bind un contrôle à la propriété d'un object. Tu peux le faire via un
NSObjectController
ou une de ses sous-classe mais c'est pas obligatoire (sauf en cas d'Array mais c'est le prochain cours 😉).Quand tu crée le binding depuis un contrôle tu "asservi" une des ses propriétés à la propriété d'un autre objet. Cocoa s'amuse ensuite à suivre les changements des deux objets afin que la valeur des propriétés bound respectives de ces derniers soient toujours égales (mais pas identiques si c'est des classes, merci NSCopying). Pour ça il utilise des méthodes genre
value(forKey:)
ousetValue(_:forKey:)
ou plus généralement tout l'attirail KVO/KVC.On va prendre un cas qu'on connait tous les deux qui est celui du code que j'ai mis sur GitHub parce qu'on a tous les deux accès au code.
Si tu prends le textfield de gauche dans la section Addition et regarde ses bindings on voit que:
NSBindingName.value
commune à tous lesNSControl
sselection
, c'est (presque) toujours le cas.addLeft
.Là concrètement on a lié la valeur du textfield à la valeur de la propriété
addLeft
de l'instance deCalculusEngine
qui est liée à l'object controller. De la même manière le text field du milieu est bound à la propriétéaddRight
du même objet et celui tout à droite àaddResult
.Quand la valeur du textfield change elle est validé par le number formatter et transmise via binding à la propriété
addLeft
de l'instanceCalculusEngine
en passant pas l'object controller. L'instanceCalculusEngine
sait que siaddLeft
change alorsaddResult
aussi (grâce àkeyPathsForValuesAffectingValue(forKey key: String) -> Set<String>
) alors, via binding, la valeur deaddResult
est envoyée à la propriétévalue
et le textfield affiche la valeur transformée par le number formatter qui lui est attaché.À aucun moment il ne faut utiliser un
@IBOutlet
pour les bindings.PS: Oui je sais que Calculus c'est pas ça en anglais.
Meric @Pyroh ,
Bon j'ai résolu le problème de "compilation", tout semble fonctionner normalement sauf un truc qui correspond à la fin de tes explications:
la fonction de calcul retourne un résultat qui devrait se retrouver dans la zone de résultat (un label) mais cela ne fonctionne pas. J'ai vérifié le bon fonctionnement de la fonction, tout est ok. la frappe au clavier est bien "suivie", le calcul est correct mais le résultat ne s'affiche pas.
Je vais creuser en relisant tes explications.
Bon ok, j'ai un peu honte car l'erreur venait du number formatter mal paramétré... merci @Pyroh .
Maintenant je me pose une autre question: comment faire pour initialiser un des champs, par exemple le champ addLeft, avec une valeur?
Encore une fois, ne vais-je pas avoir un problème de conversion vers le type décimal?
Voici un truc que j'aimerais pouvoir faire:
1- je récupère la valeur du cours de l'action Apple sur le net
2- j'affiche cette valeur dans addLeft
3- je saisis une valeur dans addRight pour le calcul...