2009-07-07 2 views
1

J'ai un plist (créé en XCode) avec un tableau complet de "Numbers" (0.01, 1, 2, 6) qui se décompresse en NSValues ​​lorsqu'il est reconstitué avec initWithContentsOfFile. Comment puis-je transformer ces NSValues ​​en NSDecimalNumbers que je peux utiliser pour additionner? Ils seront traités comme des valeurs monétaires et ne nécessitent donc qu'une précision de 2 (peut-être 4) décimales.Convertir NSValue en NSDecimalNumber

J'ai essayé d'enregistrer les valeurs de plist comme "String" au lieu de "Number" et en utilisant initWithString de NSDecimalNumber pour définir la valeur, mais NSValue ne répond pas à stringValue.

On dirait que gérer des nombres est particulièrement déroutant dans Cocoa. tant de formats de conteneurs dans tant de frameworks ... :-(

Répondre

0

La première leçon à apprendre est que lorsque vous représentez une devise, utilisez des entiers plutôt que des nombres à virgule flottante (décimale) si vous voulez une précision quelconque. par 100.0 chaque fois que vous avez besoin d'afficher cents, etc.) Les ordinateurs sont sans faille avec binaire (base 2) mais si vous essayez de représenter en binaire quelque chose qui ne peut pas être décomposé en facteurs , vous rencontrerez des erreurs de précision. (Essayez 0,1 + 0,1 et voyez ce que vous obtenez.)

Cela dit, la balise XML dans laquelle vous spécifiez le nombre fait vraiment une différence dans la façon dont les valeurs sont interprétées en termes de classes Cocoa lorsque vous utilisez quelque chose comme -[NSArray initWithContentsOfFile:] pour "reconstitue" le. Consultez le plist man page et this Apple article pour plus de détails et d'exemples.

Pour accomplir ce que vous demandez, assurez-vous que vous utilisez <real> ou <integer> (et l'étiquette de fermeture correspondante) autour des valeurs dans votre plist. (Property List Editor et Xcode doivent automatiquement utiliser la bonne en fonction de la décimale du nombre.) Dans mes tests, les nombres réels et entiers ont été lus en tant qu'objets NSNumber. NSDecimalNumber est une sous-classe de NSNumber, mais je ne suis pas entièrement sûr de la façon dont le pont sans frais avec CFNumber fonctionne dans tous les cas. L'expérimentation est probablement le meilleur moyen de comprendre cela.

+0

L'approche multiplier par 100 est idéale pour les devises MOST mais elle n'est pas universelle. Je suppose que je pourrais obtenir le maximumFractionDigits de NSNumberFormatter pour les paramètres régionaux en cours et ensuite multiplier mon entier par 10^maxDigits. Pourtant, dans cette ère moderne de l'informatique, il ne semble pas que ce soit difficile/déroutant de manipuler quelque chose d'aussi commun que la monnaie ... – Meltemi

+0

Vous avez un point, ce serait bien si ce n'était pas déroutant. Cependant, en tant que problème binaire/décimal, je ne vois pas un moyen facile à contourner à moins que nous passions notre argent à binaire. :-) –

1

Vous devriez pouvoir stocker directement vos numéros sous forme de chaînes dans la liste de propriétés. Vous n'avez pas besoin de faire un wrapping NSValue pour NSStrings lorsque vous les stockez dans un plist. Je recommande de garder les numéros dans votre application comme NSDecimals ou NSDecimalNumbers pour éviter toute erreur à virgule flottante, en les lisant depuis le plist en utilisant initWithString: locale :, et en les écrivant dans la plist avec descriptionWithLocale :. Le stockage et la récupération des décimales sous forme de chaînes évitent toute erreur de conversion à virgule flottante.