Re: NSDecimalNumber and 10.2.x: is this bug a secret?
Re: NSDecimalNumber and 10.2.x: is this bug a secret?
- Subject: Re: NSDecimalNumber and 10.2.x: is this bug a secret?
- From: "Louis C. Sacha" <email@hidden>
- Date: Sun, 29 Feb 2004 20:55:49 -0800
Hello...
I can verify that the bug exists in 10.26, although it seems to be a
bug in Core Foundation rather than NSDecimal Number.
The short answer: In 10.2.6 (and probably 10.2.8) the NSDecimalNumber
is being passed across the CF/NS toll-free bridge, and apparently the
value is ripped out of the object directly instead of calling the
CFNumberGetValue() function, so any type of NSNumber other than an
NSCFNumber does not work correctly on the CF side when a plist is
written.
If you are getting this value in a place in your code where you know
the type of number that will be entered, you could do something like
myNumber = [NSNumber numberWithFloat:[textField floatValue]];
myNumber = [NSNumber numberWithInteger:[textField intValue]];
or myNumber = [NSNumber numberWithUnsignedInt:[[textField
objectValue] unsignedIntValue]];
That way the object is an NSNumber instead of an NSDecimalNumber, and
the CFNumber equivalent works correctly for writing out to the plist.
Of course, it only works for values within the ranges of these types,
and if you don't know the exact type of number being entered you
would probably need to default to using float for the conversion.
The long answer: The following is what happens when an NSDictionary
is written out to a file in 10.2.6 (as a plist), although the process
is probably similar for other system versions. When the dictionary is
written out to a file, it goes through this process for each of the
objects:
It tests what kind of class the object instance belongs to among the
CF/NS bridged types.
if ([object isKindOfClass:[NSString class]]) {...}
if ([object isKindOfClass:[NSData class]]) {...}
if ([object isKindOfClass:[NSNumber class]]) {...}
if ([object isKindOfClass:[NSDate class]]) {...}
if ([object isKindOfClass:[NSArray class]]) {...}
if ([object isKindOfClass:[NSDictionary class]]) {...}
If an object is none of these types, the write operation fails.
If an object is one of those types, then CoreFoundation functions get
called on the bridged object
cfType = CFGetTypeID(object); // --> cfType = [object _cfTypeID];
which for an NSNumber or NSDecimalNumber instance returns
CFNumberType, which you can get from the result of
CFNumberGetTypeID(). This function is actually called twice for an
NSNumber, and then the kind of number is requested using
cfValueType = CFNumberGetType(object); // --> cfValueType =
[object _cfNumberType];
One would assume that this should be followed by the following function call
CFNumberGetValue(object, cfValueType, (void *)buffer); // -->
[object _getValue:buffer forType:cfValueType];
But it doesn't actually happen, so I'm guessing that the value is
being extracted directly from the (assumed) NSCFNumber instance,
which means that the Core Foundation code does not work correctly for
any other subclass of NSNumber (or a proxy).
So, it would appear that this is a bug in the Core Foundation code
that writes out the plist from the dictionary, not actually in
NSDecimalNumber. This also means that there is no easy way to patch
this problem when you are running pre-10.3, except for the workaround
noted above (converting to an NSNumber instance).
Since it works correctly in 10.3, either
A) Apple fixed the bug in Core Foundation for 10.3 (although they may
not technically consider it a bug since I couldn't find any place in
the documentation where it actually states that NSNumber is toll-free
bridged to CFNumber, even though the code indicates that it should
be)...
B) In 10.3 the plist is generated in Cocoa without the use of the
Core Foundation types, so the code in Core Foundation that contains
the bug is no longer used.
Hope that helps,
Louis
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.