storing [NSNull null] values in NSUserDefaults, from JSON serialization, causes unwanted exceptions
I've tried some recursive solutions but they tend to be complicated and don't handle mixed type content well. At the simplest level here is a flat example that works well if you have a predictable, flat response to clean.
NSMutableDictionary *dictMutable = [dict mutableCopy];
[dictMutable removeObjectsForKeys:[dict allKeysForObject:[NSNull null]]];
TouchJSON, dealing with NSNull
nil
and NULL
are actually both equal to zero, so they are, in practice, interchangeable. But you're right, for consistency, the documentation for TouchJSON should have used theDeserializer.nullObject = nil
instead of NULL
.
Now, when you do that, your second predicate actually works fine:
if (![jsonDataDict objectForKey:someKey])
because TouchJSON omits the key from the dictionary when you have nullObject
set to nil
(or NULL
). When the key doesn't exist in the dictionary, NSDictionary returns nil, which is zero so your if condition works as you expect.
If you don't specify nullObject
as nil
, you can instead check for null like so:
if ([jsonDataDict objectForKey:someKey] == [NSNull null])
Why is NSUserDefaults unwilling to save my NSDictionary?
Props to Kevin who suggested printing the values, of course one of which is of type NSNull
which is not a property list value. Thanks!
The kludgy solution to my problem - iterate over the keys of the dictionary I just produced so conveniently with dictionaryWithValuesForKeys
and remove those of type NSNull
. sigh
NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithDictionary:[self dictionaryWithValuesForKeys:keys]];
for( id key in [dict allKeys] )
{
if( [[dict valueForKey:key] isKindOfClass:[NSNull class]] )
{
// doesn't work - values that are entered will never be removed from NSUserDefaults
//[dict removeObjectForKey:key];
[dict setObject@"" forKey:key];
}
}
iOS, JSON-RPC and NSJSONSerialization: Dealing with null values
First of all {"telephone": "null"} is not a null value. There are quotes so actually telephone property has string value with text "null". Server needs to send {"telephone": null} - without quotes.
I'd go with listing all relevant properties that your app needs in response and put null as a value if there is not value. Then you can easily check in NSDictionary you get from NSJSONSerialization if value for key is NSNull.
if ([dictionaryValue isKindOfClass:[NSNull class]])
myThink.myProperty = nil;
NSMutableArray with [NSNull null] vs NSPointerArray
If you are putting objects in the NSMutableArray
as well, say the chess pieces, stay with NSMutableArray
. Also there is really no reason not to use [NSNull null]
, really not much different that putting a NULL in a NSPointerArray
.
If you are concerned about performance measure before making any change.
Attempt to set a non-property-list object - NSUserDefaults
You can't have null in there.
property lists do not support explicit nulls
Wikipedia
Why can I return a NSMutableArray from NSUserDefaults but not an NSMutableDictionary
just because :D
copy the dictionary like this
NSMutableDictionary *d = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"bla"].mutableCopy;
Attempt to set a non-property-list object as an NSUserDefaults
The code you posted tries to save an array of custom objects to NSUserDefaults
. You can't do that. Implementing the NSCoding
methods doesn't help. You can only store things like NSArray
, NSDictionary
, NSString
, NSData
, NSNumber
, and NSDate
in NSUserDefaults
.
You need to convert the object to NSData
(like you have in some of the code) and store that NSData
in NSUserDefaults
. You can even store an NSArray
of NSData
if you need to.
When you read back the array you need to unarchive the NSData
to get back your BC_Person
objects.
Perhaps you want this:
- (void)savePersonArrayData:(BC_Person *)personObject {
[mutableDataArray addObject:personObject];
NSMutableArray *archiveArray = [NSMutableArray arrayWithCapacity:mutableDataArray.count];
for (BC_Person *personObject in mutableDataArray) {
NSData *personEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:personObject];
[archiveArray addObject:personEncodedObject];
}
NSUserDefaults *userData = [NSUserDefaults standardUserDefaults];
[userData setObject:archiveArray forKey:@"personDataArray"];
}
Related Topics
How to Differentiate Whether a User Is Tapping the Screen with His Finger or an Apple Pencil
Having Uiview Drawrect Occur in a Background Thread
Custom Uitableviewcell with Progress Bar Download Update
iOS Appextension:How to Combine Nsextensionactivationrule and Nspredicate
Detecting iOS Version Number from User Agent Using Regular Expressions
How to Get Nsdate with Millisecond Accuracy
Change Status Bar Text Colour from White iOS 7/Xcode 5
How to Get All Nsrange of a Particular Character in a Nsstring
Programmatically Determine Current Target (Run or Test) in iOS Project
Enabling Facebook Breaking Changes Feb 2013: Login Does Not Work
Xamarin.iOS Binding Libraries/Native Frameworks
The Proper Way of Doing Chain Animations
Swift Spritekit Facebook Share Button
Add Button at the End of Collection View in Storyboard
Avassetresourceloaderdelegate Methods Not Working on Device
How to Load Multiple Storyboard Files Depending on iOS Version? (5 and 6)