HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Parsing NSDictionary from NSJSONSerialization

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
fromnsdictionaryparsingnsjsonserialization

Problem

playerObject is an NSDictionary from JSONObjectWithData:options:error.

I'm trying to update a CoreData entity.

if ([results count] > 0)
{
    newPlayer = (Player *)[results objectAtIndex:0];
} else {
    //Add a new player
    newPlayer = [NSEntityDescription insertNewObjectForEntityForName:@"Player" inManagedObjectContext:temporaryContext];
}
//Assume these exist and are not null
newPlayer.email = [playerObject objectForKey:@"email"];
newPlayer.username = [playerObject objectForKey:@"username"];
newPlayer.continent = [playerObject objectForKey:@"continent"];

//Dates
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:@"yyyy-MM-dd hh:mm:ss"];
newPlayer.created = [df dateFromString: [playerObject objectForKey:@"created"]];

//Optional properties
if ([[playerObject objectForKey:@"title"] isKindOfClass:[NSNull class]])
{
    newPlayer.title = nil;
} else {
    newPlayer.title = [[playerObject objectForKey:@"title"] stringValue];
}


Is there any way to make it less verbose? Have I left myself open to any issues?

Solution

if ([results count] > 0)
{
    newPlayer = (Player *)[results objectAtIndex:0];
} else {
    //Add a new player
    newPlayer = [NSEntityDescription insertNewObjectForEntityForName:@"Player" inManagedObjectContext:temporaryContext];
}


This chunk of code could be replaced with:

newPlayer = (Player *)([results firstObject] ?: [NSEntityDescription insertNewObjectForEntityForName:@"Player" inManagedObjectContext:temporaryContext]);


if ([[playerObject objectForKey:@"title"] isKindOfClass:[NSNull class]])
{
    newPlayer.title = nil;
} else {
    newPlayer.title = [[playerObject objectForKey:@"title"] stringValue];
}


This chunk of code could also be slightly better.

NSString *newTitle = playerObject[@"title"];
newPlayer.title = [newTitle isEqual:[NSNull null]] ? nil : [newTitle stringValue];


The last comment that I'll make is a strong recommendation that you use constants for your keys rather than literal strings. Defined constants will auto-complete for you, which is nice, but more importantly, it will eliminate misspellings entirely.

static NSString * const kKey_Player = @"Player";
static NSString * const kKey_Title = @"title";
// etc.


Then use it as such:

NSString *newTitle = playerObject[kKey_Title];


Under the covers, this actually doesn't change in the slightest what the code does. Even when you use string literals, a memory location is still allocated for them. The advantage here is that you eliminate programmer mistakes.

Code Snippets

if ([results count] > 0)
{
    newPlayer = (Player *)[results objectAtIndex:0];
} else {
    //Add a new player
    newPlayer = [NSEntityDescription insertNewObjectForEntityForName:@"Player" inManagedObjectContext:temporaryContext];
}
newPlayer = (Player *)([results firstObject] ?: [NSEntityDescription insertNewObjectForEntityForName:@"Player" inManagedObjectContext:temporaryContext]);
if ([[playerObject objectForKey:@"title"] isKindOfClass:[NSNull class]])
{
    newPlayer.title = nil;
} else {
    newPlayer.title = [[playerObject objectForKey:@"title"] stringValue];
}
NSString *newTitle = playerObject[@"title"];
newPlayer.title = [newTitle isEqual:[NSNull null]] ? nil : [newTitle stringValue];
static NSString * const kKey_Player = @"Player";
static NSString * const kKey_Title = @"title";
// etc.

Context

StackExchange Code Review Q#15059, answer score: 2

Revisions (0)

No revisions yet.