How to remove Objective-C @try @catch blocks like this?

I am a Python developer using exceptions. In many places, I found that using exceptions is not so wise here, and I did my best to convert it to NSErrors when necessary. but then I come across this:

NSMutableArray *results; for (NSDictionary *dict in dicts) { // Memory management code omitted SomeModel *model = [[SomeModel alloc] init]; model.attr1 = [[dict objectForKey:@"key1"] integerValue]; model.attr2 = [[dict objectForKey:@"key2"] integerValue]; model.attr3 = [[dict objectForKey:@"key3"] integerValue]; model.attr4 = [[dict objectForKey:@"key4"] integerValue]; [results addObject:model]; } 

with some objects in a dict containing NSNull, which will result in an โ€œunrecognized selectorโ€ exception. In this case, I want to completely abandon this database. My first instinct is to wrap all the contents of a for block in a catch @@ catch block:

 NSMutableArray *results; for (NSDictionary *dict in dicts) { @try { SomeModel *model = [[SomeModel alloc] init]; model.attr1 = [[dict objectForKey:@"key1"] integerValue]; model.attr2 = [[dict objectForKey:@"key2"] integerValue]; model.attr3 = [[dict objectForKey:@"key3"] integerValue]; model.attr4 = [[dict objectForKey:@"key4"] integerValue]; [results addObject:model]; } @catch(NSException *exception) { // Do something } } 

But is this a good approach? I can't come up with a solution without repeating the checks for each variable, which is a really ugly IMO. I hope there are alternatives to this that are not met with me. Thanks in advance.

+4
source share
3 answers

Many people use a category in NSDictionary for these cases:

 - (id)safeObjectForKey:(id)aKey { id obj = [self objectForKey:aKey]; if ([obj isKindOfClass:[NSNull class]]) { return nil; } return obj; } 

You still need to make sure your dict is the actual instance of the dictionary.

+1
source

The correct way for Objective-C to do this:

 for (NSDictionary *dict in dicts) { if (! [dict isKindOfClass:[NSDictionary class]]) continue; // ... } 

Testing if the recipient can respond to the message before sending it is a typical pattern in Objective-C.

Also note that exceptions in Objective-C are always a programmer error and are not used for normal execution flow.

+3
source

In the end, I decided to solve the problem using KVC. Something like that:

 - (id)initWithPropertyDictionary:(NSDictionary *)dict lookUpTable:(NSDictionary *)keyToProperty { self = [self init]; for (NSString *key in dict) { NSString *propertyName; if ([keyToProperty objectForKey:key]) propertyName = [keyToProperty objectForKey:key]; else propertyName = key; if ([[dict objectForKey:key] isKindOfClass:[NSNull class]]) { [self release]; return nil; } else { [self setValue:[dict objectForKey:key] forKey:propertyName]; } } } 

The rejection of this permission is that I will have to use NSNumber for my properties, but for JSON data there really is no difference between floating numbers and integers, so this is normal.

And if you really want primitive types, you can associate this method with custom installers that convert NSNumbers to the corresponding types.

That being said, all you have to do is check the nil value before adding the object to the array. Much cleaner everywhere except the model class.

Thanks to jaydee3 for inspiring me to focus on changing the model class.

0
source

Source: https://habr.com/ru/post/1443200/


All Articles