"How to serialize a custom object in NSDictionary using JSON in XCode?"
Chalk up another reason why I loathe XCode, and wish someone would drag it from the 1990s.
Let's go through an example of how we're expected to serialize a custom object.
Supposing you had a very simple UserRecord class, with a .h file like this:
@interface UserRecord : NSObject
@property(nonatomic) int UserID;
@property(nonatomic, strong) NSString* FirstName;
@property(nonatomic, strong) NSString* LastName;
@property(nonatomic) int Age;
@end
And an .m like this:
@implementation UserRecord
@synthesize UserID;
@synthesize FirstName;
@synthesize LastName;
@synthesize Age;
@end
If you tried to create a UserRecord object, and serialize it using the NSJSONSerialization class..
UserRecord* sampleRecord = [[UserRecord alloc] init];
sampleRecord.UserID = 13;
sampleRecord.FirstName = @"Mike";
sampleRecord.LastName = @"Gledhill";
sampleRecord.Age = 82;
NSError* error = nil;
NSData* jsonData2 = [NSJSONSerialization dataWithJSONObject:sampleRecord options:NSJSONWritingPrettyPrinted error:&error];
..it'd laugh at you, throw an exception and crash your application:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[NSJSONSerialization dataWithJSONObject:options:error:]: Invalid top-level type in JSON write'
One way to get around this farce is to add a function to your NSObject
to convert your data into an NSDictionary
, and then serialize that.
Here's my new .m file for my class:
@implementation UserRecord
@synthesize UserID;
@synthesize FirstName;
@synthesize LastName;
@synthesize Age;
-(NSDictionary*)fetchInDictionaryForm
{
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
[dict setObject:[NSNumber numberWithInt:UserID] forKey:@"UserID"];
[dict setObject:FirstName forKey:@"FirstName"];
[dict setObject:LastName forKey:@"LastName"];
[dict setObject:[NSNumber numberWithInt:Age] forKey:@"Age"];
return dict;
}
@end
Actually, you could create that NSDictionary
value in one go, if you wanted to:
-(NSDictionary*)fetchInDictionaryForm
{
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:UserID], @"UserID",
FirstName, @"FirstName",
LastName,@"LastName",
[NSNumber numberWithInt:Age], @"Age",
nil];
return dict;
}
Once you've done this, you can get NSJSONSerialization
to serialize the NSDictionary
version of your object:
UserRecord* sampleRecord = [[UserRecord alloc] init];
sampleRecord.UserID = 13;
sampleRecord.FirstName = @"Mike";
sampleRecord.LastName = @"Gledhill";
sampleRecord.Age = 82;
NSDictionary* dictionary = [sampleRecord fetchInDictionaryForm];
if ([NSJSONSerialization isValidJSONObject:dictionary])
{
NSError* error = nil;
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:dictionary options:NSJSONWritingPrettyPrinted error:&error];
NSString* jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(@"%@", jsonString);
}
And this will produce the JSON output we wanted:
{
"UserID" : 13,
"FirstName" : "Mike",
"LastName" : "Gledhill",
"Age" : 82
}
It's shocking. Even in 2015, Apple's SDK isn't capable of serializing a simple set of int
s and NSString
s into JSON.
Hope this helps other XCode victims.