2016-05-31 17 views
1

Meine App erinnert sich an MPMediaItems per persistentId, so wie man es tut. Es speichert die persistentId in einer JSON-Datei, die später gelesen und analysiert wird. NSJSONSerialization erstellt eine NSDecimalNumber, die die ID enthält, die meine Anwendung später in einer MPMediaQuery verwendet, um das MPMediaItem abzurufen.NSDecimalNumber gibt einen falschen Wert zurück uint64_t

Was ich fand, ist, dass manchmal das falsche MPMediaItem gefunden wird. Als ich noch ein bisschen herumstöberte, entdeckte ich, dass, wenn ich die NSDecimalNumber in einen uint64_t-Wert umwandelte, [NSNumber unsignedLongLongValue] den falschen Wert zurückgab!

NSDecimalNumber* const songId = _songId; 
uint64_t   const songIdValue = songId.unsignedLongLongValue; 

songId is  1457249251113381177 
songIdValue is 1457249251113381120 
-or- 
songId is  0x1439307919d12d39 
songIdValue is 0x1439307919d12d00 

Was zum Teufel? Es sieht so aus, als ob das Low-Byte bei der Konvertierung dieser NSDecimalNumber in einen Uint64_t gelöscht wird. Ist das irgendwie richtiges Verhalten für NSDecimalNumber von habe ich einen Bug darin gefunden?

Ich arbeite um dies durch Umwandlung der NSDecimalNumber aus NSJSONSerialization in eine Zeichenfolge und Konvertieren der Zeichenfolge in eine Uint64_t mit [NSString longLongValue].

Es ist beängstigend, dass es scheint, ich habe jetzt gehen und überprüfen JEDER Stelle, die ich speichern große Ganzzahlen in JSON-Dateien und stellen Sie sicher, dass ich sie in dieser NSString-y Weise evaluieren.

+0

Ich habe hier einen Kommentar gefunden, der besagt, dass NSDecimalNumber in ein Double konvertiert und dann in ein Uint64_t konvertiert wird. Daher werden alle signifikanten Bits jenseits von 53 gelöscht, wie ich hier gesehen habe. Unglaublich, dass Apple das aufgibt! NSJsonSerialization irrt sich bei der Auswahl dieser Klasse für Ganzzahlen und nicht für NSNumber. Ich werde mein JSON-Parsing in JSONKit umwandeln, und ich würde jedem anderen empfehlen, dasselbe zu tun. –

+0

In seinem Kommentar bezieht sich Christopher vielleicht auf [diese Antwort auf * NSDecimalNumber und große unsigned long long (64-bit) Ganzzahlen *] (http://stackoverflow.com/questions/6710469/nsdecimalnumber-and-large-unsigned-long) -long-64-Bit-Ganzzahlen/6713550 # 6713550) – CRD

Antwort

0

Wenn Sie ein Höchstmaß an Präzision halten möchten, können Sie:

Arbeit nur mit NSDecimalNumbers,

ein NSString verwenden, wenn Sie den Wert eines NSDecimalNumber auf eine andere Variable übertragen, die kein NSDecimalNumber ist. Die Methoden wie [NSDecimalNumber longLongValue] oder [NSDecimalNumber doubleValue] sind nicht spezifisch genug.

NSDecimalNumber  *songId; 
uint64_t   songIdValue; 
NSString   *intermediateStr; 

songId = [NSDecimalNumber decimalNumberWithString:@"1457249251113381177"]; 
intermediateStr = songId.stringValue; 
songIdValue = intermediateStr.longLongValue; 

Warum die Verwendung von Strings ist genauer als andere Methoden? Ich weiß es nicht. Aber songIdValue enthält den richtigen Wert ohne Verlust.