Curt Rand
Curt Rand

Reputation: 1045

Objective C: Is it good practice to check JSON values if it is the type you expect?

Currently, I am checking if the JSON value is an NSString and if it isn't, assign the property a default string. This way I can prevent the app from crashing if the JSON value is null and I can return a User object with a default first name and last name.

// User model

+ (Email *)getEmailInfoWithDictionary:(id)dict {
  Email *email = [[self alloc] init];
  if ([dict isKindOfClass:[NSDictionary class]]) {
    user.firstname = [NSString checkType:dict[@"firstname"] defaultString:@"John"];
    user.lastname = [NSString checkType:dict[@"lastname"] defaultString:@"Smith"];
  }
}
return user;
}

// NSString category method.

+ (NSString *)checkType:(id)obj defaultString:(NSString *)def {
  if (obj == nil || ![obj isKindOfClass:[NSString class]]) {
    return def;
  }
  return obj;
}

I have a couple of concerns, however. Is it a good idea to always check for null values regarding json values so this way you won't get crashes? I've noticed some Objective C tutorials that don't do this. Makes me wonder if I shouldn't worry about this and I should expect the API to return the correct values. My second concern is the method I am using a good idea or is a there better way?

Upvotes: 1

Views: 204

Answers (2)

rmaddy
rmaddy

Reputation: 318814

Is it a good idea to always check for null values regarding json values so this way you won't get crashes?

Makes me wonder if I shouldn't worry about this and I should expect the API to return the correct values.

Yes, definitely a good idea to check. Never assume that the data you obtain from a 3rd party is ever going to be what you expect. APIs change. Bugs happen. Code defensively whenever you deal with data that isn't 100% in your control. Better to show an error to the user or handle the unexpected data in some graceful manner than have your app crash because you expected a string and got a number or you got a single dictionary instead of an array of dictionary, etc.

My second concern is the method I am using a good idea or is a there better way?

There's no good answer here. Every use case is different. How you handle bad data depends on the data and how bad it is. For a simple case like a missing or invalid name, providing a default may or may not be appropriate. That's up to you and your app. It may be better to skip the record or show an error to the user. Or you choice of defaulting to some value is just fine if that makes sense for your situation.

Upvotes: 1

Jeffery Thomas
Jeffery Thomas

Reputation: 42588

I would say start by leaning into Objective-C's default handling of nil. In most cases, nil will do what you want without crashing. In contrast, [NSNull null] is poorly designed and a constant problem.

@interface NSObject (MyCasting)
- (NSString *)stringOrNil;
- (NSNumber *)numberOrNil;
- (NSDictionary *)dictionaryOrNil;
- (NSArray *)arrayOrNil;
@end

@implementation NSObject (MyCasting)

- (NSString *)stringOrNil {
    return [self isKindOfClass:NSString.class] ? (NSString *)self : nil;
}

- (NSNumber *)numberOrNil {
    return [self isKindOfClass:NSNumber.class] ? (NSNumber *)self: nil;
}

- (NSDictionary *)dictionaryOrNil {
    return [self isKindOfClass:NSDictionary.class] ? (NSDictionary *)self: nil;
}

- (NSArray *)arrayOrNil {
    return [self isKindOfClass:NSArray.class] ? (NSArray *)self: nil;
}

@end

This will provide you with a good level of safety using nil as the default value.

+ (Email *)getEmailInfoWithDictionary:(id)dict {
    Email *email = [[self alloc] init];
    NSDictionary *dictionary = [dict dictionaryOrNil];

    email.firstname = [dictionary[@"firstname"] stringOrNil];
    email.lastname = [dictionary[@"lastname"] stringOrNil];

    return email;
}

If you feel you need the additional safety of object default values, then you can use the ?: operator.

email.firstname = [dictionary[@"firstname"] stringOrNil] ?: "";
email.lastname = [dictionary[@"lastname"] stringOrNil] ?: "";

Upvotes: 1

Related Questions