如何消除像这样的Objective-C@try@catch块?

如何消除像这样的Objective-C@try@catch块?,objective-c,Objective C,我是一名来自Python世界的开发人员,习惯于使用异常。我在许多地方发现,在这里使用异常并不是那么明智,并在需要时尽我所能转换为N错误。但后来我遇到了这样的情况: NSMutableArray *results; for (NSDictionary *dict in dicts) { // Memory management code omitted SomeModel *model = [[SomeModel alloc] init]; model.attr1 = [[

我是一名来自Python世界的开发人员,习惯于使用异常。我在许多地方发现,在这里使用异常并不是那么明智,并在需要时尽我所能转换为N错误。但后来我遇到了这样的情况:

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];
}
dict中的某些对象包含NSNull,这将导致“无法识别的选择器”异常。在这种情况下,我想完全删除该数据。我的第一反应是将for块的全部内容包装成一个@try-@catch块:

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
    }
}

但这是一个好办法吗?如果不对每个变量进行重复检查,我就无法想出一个解决方案,这在我看来真的很难看。希望我没有想到其他替代方法。提前感谢。

正确的Objective-C方法是:

for (NSDictionary *dict in dicts)
{
    if (! [dict isKindOfClass:[NSDictionary class]])
        continue;
    // ...
}
在Objective-C中,测试接收者在发送消息之前是否能够响应消息是一种典型模式


另外,请注意Objective-C中的异常始终是程序员错误,不会用于正常的执行流。

许多人在这些情况下使用NSDictionary上的类别:

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

  return obj;
}

您仍然需要确保您的dict是一个实际的字典实例。

最后,我决定使用KVC解决这个问题。大概是这样的:

- (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];
        }
    }
}
这个解决方案的缺点是,我必须在属性中使用NSNumber,但是对于JSON数据,浮点数和整数之间实际上没有区别,所以这很好

如果您真的需要基元类型,可以将此方法与将这些NSNUMBER转换为适当类型的自定义设置器耦合

这样,在将对象添加到数组中之前,只需检查nil。除了模型类,其他地方都要干净得多


感谢Jayde3启发我专注于更改模型类。

Objective-C的基本规则是
@try/catch
意味着您的程序将崩溃,并且将无法继续执行。如果“该数据”指的是:整个SomeModel对象,那么您使用try-catch的方法就可以了。没有规则禁止使用try-catch。如果“数据”的意思是:某个模型的特定属性,那么Jayde3的回答为您提供了一个很好的方法。我意识到在这里使用异常可能不是一个好主意,但是除了检查我的每一个条目,我真的没有别的选择吗?我相信要求是处理
NSNull
的词典条目,而不是整个词典。@janusfidel苹果的所有代码都经过了优化,在
O(0)
中运行。除非他们决定不再支持某个设备,否则他们会让它在
O(n!!)
中运行。为什么要专门检查
NSNull
?这似乎并不能解决问题……这正是我们所要求的。这是解析JSON后的常见问题。您可以在
nil
对象上发送任何消息,但不能在
NSNull
对象上发送任何消息。在他的情况下,调用
integerValue
会发生崩溃。如果返回nil,它不会崩溃。但是在这种情况下,您是否应该检查
而不是(![obj isKindOfClass:[NSNumber class]])
呢?一般的问题是您会得到
NSNull
对象。你不能打电话给他们。通常,您希望从任何API获得特定类型。您需要实际数据,如果没有数据,则为零。NSNull是第三种情况,如果使用此类别,则不需要处理。当然,最好检查示例中所期望的每种类型。但这是一种更通用的方法,在大多数情况下已经足够了。哇,我想这是一个常见的问题,因为我甚至没有在我的帖子中提到我在解析。这并不能完全解决我的问题,因为我的主要诉求是有一种简单的方法来删除错误的数据,但我想如果我们以不同的方式查看数据,这是可以的。如果没有更好的东西出现,我会把这个标记为正确的。