我最近被告知将[NSNull null]
投射到(NSString*)
是“可怕的”。
但是,如果密钥不在字典中,-[NSDictionary stringForKey:]
方法将返回[NSNull null]
,如果我不进行强制转换,编译器会对我大喊大叫。
我错过了什么吗?
编辑:
我的错误......我想我可能会开始看到这个问题......
正如大家所指出的那样,NSDictionary上没有stringForKey:方法,是的,当我问这个问题时我正在考虑用户默认值...所以我回去看看我在做什么......这是:
NSString * someValue = (NSString*)[myDictionary objectForKey:@"key"];
if (someValue == (NSString*)[NSNull null]) ...
如果我在这种情况下不进行演员表,我会收到以下错误:
warning: comparison of distinct Objective-C types 'struct NSNull *' and 'struct NSString *' lacks a cast
施放值“解决”了问题,我宁愿不写10行,其中一行会做...
这不好吗?我会在哪里遇到问题?
另外:
字典来自JSON库...在这种情况下,NULL是有效值,因此,如果缺少密钥,可能不是NSDictionary返回它们,而是密钥实际上是在那里,并且该值实际上为空。
答案 0 :(得分:14)
NSDictionary
不会返回NSNull
的实例,除非您或其他来源将它们放在那里。同样,NSDictionary
也不会回复-stringForKey:
。您是否在考虑NSUserDefaults
?
如果您有一个NSDictionary
的实例,而您想要做的就是从中获取一个字符串,您可以尝试类似下面的代码。
NSString *MyGetString(NSDictionary *dict, id key, NSString *fallback) {
id result = [dict objectForKey: key];
if (!result)
result = fallback;
else if (![result isKindOfClass: [NSString class]])
result = [result description];
return result;
}
将后备字符串作为fallback
传递 - 如果没有对象与键key
相关联,函数将使用该字符串。
答案 1 :(得分:7)
正如Jonathan的代码所示,如果你使用isKindOfClass:
方法会更好。即使您更改了检索对象的方法等,它也会保护您,并且是一种更准确的检查。
另请注意,[someValue isKindOfClass:[NSString class]]
仅在YES
不是someValue
并且nil
时返回NSString
,这意味着它也足以进行nil
}值。
答案 2 :(得分:6)
演员阵容“糟糕”,因为NSNull
不是 NSString
。转换不会改变指向的对象的实际类型,它只会改变编译器的,嗯,态度。
在所示的非常特殊的情况下,你将要对象执行的仅事情是对指针平等的直接测试,你的方法将起作用,但它是潜在未来的来源错误。这种使编译器警告变得沉默的hacky会让人感到不安,如果有更好的方法,应该避免使用。
当然,真正的问题是之前的演员表,其中来自NSObject*
的{{1}}直接投放到objectForKey:
而没有问题。目前你可以逃脱它,因为你认为你只能得到字符串或NSString*
,但是如果JSON库发生变化或者只是不履行合同会发生什么?你最好做一些像:
NSNull
答案 3 :(得分:3)
您可以使用此类别扩展来包装此逻辑。 它在github上
的NSDictionary + Verified.h :
// NSDictionary+Verified.h
//
// Created by alexruperez on 08/05/13.
// Copyright (c) 2013 alexruperez. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSDictionary (Verified)
- (id)verifiedObjectForKey:(id)aKey;
@end
的NSDictionary + Verified.m :
NSDictionary+Verified.m
#import "NSDictionary+Verified.h"
@implementation NSDictionary (Verified)
- (id)verifiedObjectForKey:(id)aKey
{
if ([self objectForKey:aKey] && ![[self objectForKey:aKey] isKindOfClass:[NSNull class]]) return [self objectForKey:aKey];
return nil;
}
@end
答案 4 :(得分:1)
对NULL检查的一个很好的测试,特别是在测试网络API(特别是JSON)的解析结果时,是isEqual:
方法。我使用...测试存在和可用值
NSString *someValue = [response objectForKey:MyAPIKeySomeValue];
if (!!someValue && ![someValue isEqual:[NSNull null]]) {
// optionally test for class type
// use someValue
}
else {
// error out for required values; skip for optional values
}
更一般地说,如果您期望特定格式的JSON,并且API不符合该要求,您可以考虑将@try/@catch
包裹起来。然后,您可以处理异常/非法响应格式,并消除无效数据格式的硬崩溃。
如果格式定义松散,您可以通过构建有意义的NSError
来让您的解析例程更加优雅地失败。