Reputation: 345
I couldn't store an NSArray in NsUserDefaults
. The app gets crashed
in this line
[savedData setObject:jsonValue forKey:@"JSONDATA"];
Below is my code. and i have mention my log error below
NSArray *jsonValue =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults];
[savedData setObject:jsonValue forKey:@"JSONDATA"];
[savedData synchronize];
Error log:
*** Terminating app due to uncaught exception '`NSInvalidArgumentException`', reason: '*** -
[NSUserDefaults setObject:forKey:]: attempt to insert non-property list object <CFBasicHash 0x8c62b10 [0x1d2aec8]>{type = immutable dict, count = 3,
entries =>
Upvotes: 13
Views: 15834
Reputation: 1523
Yes they can not be saved like this in NSUserDefaults.
I am writing a code below please have a look and for more study go look apple docs okay.
Code is here:
//For Saving
NSData *dataSave = [NSKeyedArchiver archivedDataWithRootObject:yourArrayToBeSave]];
[[NSUserDefaults standardUserDefaults] setObject:dataSave forKey:@"array"];
[[NSUserDefaults standardUserDefaults] synchronize]; // this will save you UserDefaults
//For retrieving
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"array"];
NSArray *savedArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
Upvotes: 43
Reputation: 4429
NSUserDefaults should only be used for up to 500k of data (https://forums.developer.apple.com/message/50696#50696)
If storing larger amounts apps may crash, from personal experience I've seen apps storing 1MB of data crashing at/shortly after [NSUserDefaults setObject:] and [NSUserDefaults synchronise];
To check how much data a live app is using, open Xcode -> Window -> Devices, select your Device, select your app in Installed Apps and download the App Container. Defaults are stored in AppData->Preferences->your.app.plist
An alternative to saving data to the user defaults is to write to a file:
-(void)saveObject:(NSObject *)object toFile:(NSString *)name {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:name];
[NSKeyedArchiver archiveRootObject:object toFile:appFile];
}
-(NSObject *)loadFromFile:(NSString *)name {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:name];
if([[NSFileManager defaultManager] fileExistsAtPath:appFile])
return [NSKeyedUnarchiver unarchiveObjectWithFile:appFile];
else{
NSLog(@"No File: %@", name) ;
return nil ;
}
}
Upvotes: 0
Reputation: 52538
NSUserDefaults accepts property list objects - NSDictionary, NSArray, NSString, NSNumber, NSDate and NSData. JSON documents contain NSDictionary, NSArray, NSString, NSNumber and NSNull. You see the difference - property list objects cannot contain NSNull values.
If your JSON object contains an NSNull object (the JSON document that you parsed contained a "null" value), then you can't store it into NSUserDefaults. Apart from that, all the comments saying that you can't store JSON data in NSUserDefaults are nonsense. It's only NSNull objects that cause a problem.
There is a very, very simple solution to your problem. Just store the original json data as an NSData object in NSUserDefaults. Then when you read the NSUserDefaults, you get the NSData and parse them. Instead of
NSArray *jsonValue =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults];
[savedData setObject:jsonValue forKey:@"JSONDATA"];
[savedData synchronize];
you just write
NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults];
[savedData setObject:data forKey:@"JSONDATA"];
[savedData synchronize];
Upvotes: 1
Reputation: 5369
I think jsonValue is NSDictionary not NSArray..
id jsonValue = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
if ([jsonValue isKindOfClass:[NSDictionary class]])
{
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:jsonvalue];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"JSONDATA"];
[savedData synchronize];
}
//(OR)
NSDictionary *jsonValue =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:jsonvalue];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"JSONDATA"];
[savedData synchronize];
Also I think you cannot store the NSDictionary directly into NSUserDefaults..Go through @kshitij godara to get it done/save..
You can use NSKeyedArchiver to write out your dictionary to an NSData.
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:jsonvalue];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"JSONDATA"];
For retrieving data:
NSData *dictionaryData = [defaults objectForKey:@"JSONDATA"];
NSDictionary *dictionary = [NSKeyedUnarchiver unarchiveObjectWithData:dictionaryData];
Hope this helps you..!
Upvotes: 1
Reputation: 8945
try like this
NSMutableArray *jsonValue =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSData *yourEncodedObject = [NSKeyedArchiver archivedDataWithRootObject: jsonValue];
NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults];
[userData setObject: yourEncodedObject forKey:@"JSONDATA"];
[savedData synchronize];
Upvotes: 1
Reputation: 5149
While kshitij's answer is correct, sadly, it doesn't end there. If you want to save custom objects inside your NSUserDefaults
, your custom object has to implement the NSCoding
protocol and override the initWithCoder
and encodeWithCoder
methods. An example of such can be like:
@interface Book : NSObject <NSCoding>
@property NSString *title;
@property NSString *author;
@property NSUInteger pageCount;
@property NSSet *categories;
@property (getter = isAvailable) BOOL available;
@end
@implementation Book
#pragma mark - NSCoding
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (!self) {
return nil;
}
self.title = [decoder decodeObjectForKey:@"title"];
self.author = [decoder decodeObjectForKey:@"author"];
self.pageCount = [decoder decodeIntegerForKey:@"pageCount"];
self.categories = [decoder decodeObjectForKey:@"categories"];
self.available = [decoder decodeBoolForKey:@"available"];
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.title forKey:@"title"];
[encoder encodeObject:self.author forKey:@"author"];
[encoder encodeInteger:self.pageCount forKey:@"pageCount"];
[encoder encodeObject:self.categories forKey:@"categories"];
[encoder encodeBool:[self isAvailable] forKey:@"available"];
}
@end
Upvotes: 3