Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 什么';这是防止';无法识别的选择器';对于从NSDictionary返回的对象_Objective C - Fatal编程技术网

Objective c 什么';这是防止';无法识别的选择器';对于从NSDictionary返回的对象

Objective c 什么';这是防止';无法识别的选择器';对于从NSDictionary返回的对象,objective-c,Objective C,我有以下代码,其中我从服务器获得响应,并尝试解析错误消息 我注意到,有时消息对象没有返回NSDictionary类型,会使应用程序崩溃。我想知道防止这种情况发生的最佳做法是什么?一般来说,我尽量避免进行instanceof检查。同样,也有选择器检查。感觉应该有更好的方法来实现这一点,而不是显式地检查是否允许使用我期望的那些方法/返回类型 NSDictionary *message = [serverErrorJSON objectForKey:@"message"]; if (message !

我有以下代码,其中我从服务器获得响应,并尝试解析错误消息

我注意到,有时消息对象没有返回NSDictionary类型,会使应用程序崩溃。我想知道防止这种情况发生的最佳做法是什么?一般来说,我尽量避免进行instanceof检查。同样,也有选择器检查。感觉应该有更好的方法来实现这一点,而不是显式地检查是否允许使用我期望的那些方法/返回类型

NSDictionary *message = [serverErrorJSON objectForKey:@"message"];
if (message != nil) {
return [message objectForKey:@"form"];
}
在语法上和编程上都使用文字语法是很好的

您也不必将它们链接在一起,您可能希望使用JSON的另一个属性

if ([serverErrorJSON isKindOfClass:NSDictionary.class]) {
  NSDictionary *message = serverErrorJSON[@"message"];
  //...
  return message[@"form"];
}

return nil;

防止无法识别的选择器错误的最佳方法是根据您的用例检查
respondsToSelector
isKindOfClass

不幸的是,如果您发现自己经常需要验证某个对象是否是字典,那么您的代码可能会变得非常混乱,这种情况在数据结构中嵌套字典的情况下也会发生

您可以通过添加一个类别来清理:

@interface NSDictionary (Safe)

//Returns objectForKey if dictionary param is valid, else returns nil
+ (id) _safeObjectForKey: (NSString*) key
                    dict: (NSDictionary*) dictionary;

@end

@implementation NSDictionary (Safe)

+ (id) _safeObjectForKey:(NSString *)key
                    dict:(NSDictionary *)dictionary {

    if ([dictionary isKindOfClass:[NSDictionary class]]) {
        return [dictionary objectForKey:key];
    }
    return nil;

}

@end
然后使用它,给出您的示例:

NSDictionary *message = [NSDictionary _safeObjectForKey: @"message"
                                                   dict: serverErrorJSON];
return [NSDictionary _safeObjectForKey:@"form"
                                  dict:message];
您也可以对其他常见的无法识别的选择器错误生成器执行类似操作,如NSArray的
objectAtIndex
等。

您的代码:

NSDictionary *message = [serverErrorJSON objectForKey:@"message"];
if (message != nil) {
    return [message objectForKey:@"form"];
}
这里出现“无法识别的选择器”的原因是
[serverErrorJSON objectForKey:@“message”]
没有像您预期的那样返回NSDictionary。由于您正在对该对象调用
objectForKey:
,因此建议使用
respondsToSelector:
包装该调用:

id message = nil;
if ([serverErrorJSON respondsToSelector:@selector(objectForKey:)]){
    message = [serverErrorJSON objectForKey:@"message"];
    if ([message respondsToSelector:@selector(objectForKey:)]){
        return [message objectForKey:@"form"];
    }
}

这将测试您正在调用的选择器(方法)是否存在,并且比使用
isKindOfClass:
等更安全、更兼容。测试功能总是比测试类名等更好。你不关心对象是否是NSDictionary,你关心的是它是否可以使用你调用的方法签名为一个键提供一个对象。

不,检查对象是否响应选择器:是查看它是否响应选择器的最佳方法。但是,更好的做法是确保API返回一致的响应。值得注意的是,Swift中的模板系统将解决此问题。字典和数组元素将是强类型的。Alex,这肯定是我对re的第一个想法:这更像是核心的API问题。在这里也有一些安全性(使用断言或日志记录在有东西通过时发出通知),这并没有什么害处。亚历克斯,很高兴知道!也许应该开始过渡到:)出于好奇,使用文字语法有什么好处?当然,在某些情况下,您可能希望检查
conformsToProtocol
respondsToSelector
,而不是使用
isKindOfClass
@nazbot请参见:谢谢@olivertkinson,非常有用。有人能解释一下-1吗?我完全理解我所采用的方法是非传统的,但它对我来说很有效,创建这样的方便分类方法可以帮助我更快地编写代码,减少所需的行数。不用担心,如果我应该得a-1,我只想了解为什么我可以改进自己的编码习惯。如果你不喜欢这种方法,请给我反馈!
id message = nil;
if ([serverErrorJSON respondsToSelector:@selector(objectForKey:)]){
    message = [serverErrorJSON objectForKey:@"message"];
    if ([message respondsToSelector:@selector(objectForKey:)]){
        return [message objectForKey:@"form"];
    }
}