Swift: 无法识别的选择器发送到实例,如何检测空值?
Swift: unrecognized selector sent to instance, how to detect null value?
我正在尝试使用 Microsoft Graph iOS SDK and followed the official code sample。
以下代码片段用于获取组织中所有用户的基本资料:
private func getContactInfo(){
self.graphClient.users().request().getWithCompletion{
(collection: MSCollection?, request:MSGraphUsersCollectionRequest?, error: NSError?) in
if let users = collection {
for user: MSGraphUser in users.value as! [MSGraphUser] {
print(user)
print(String(user.surname.dynamicType))
print(user.mobilePhone)
}
}
}
}
输出结果:
{
businessPhones = (
);
displayName = "Boss";
givenName = "Jack";
id = "30fb78ff-522f-45e7-a9cd-75ba8ee2eca6";
jobTitle = "<null>";
mail = "boss@abc.net";
mobilePhone = "<null>";
officeLocation = "<null>";
preferredLanguage = "<null>";
surname = "\U8a79";
userPrincipalName = "boss@abc.net";
}
ImplicitlyUnwrappedOptional<String>
并且发生了运行时异常
2016-06-05 17:02:55.302 ABC[76976:915052] -[NSNull _fastCStringContents:]: unrecognized selector sent to instance 0xb59398
2016-06-05 17:02:55.305 ABC[76976:915052] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull _fastCStringContents:]: unrecognized selector sent to instance 0xb59398'
*** First throw call stack:
(
0 CoreFoundation 0x0092c494 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x02640e02 objc_exception_throw + 50
...
当我尝试像 mobilePhone 一样打印空值时,发生了运行时异常。如何检测空值以避免崩溃?谢谢。
添加:MSGraphUser.m片段在本例中使用,
@interface MSGraphUser()
{
...
NSString* _mobilePhone;
...
- (NSString*) mobilePhone
{
return self.dictionary[@"mobilePhone"];
}
...
看起来 mobilePhone
实际上可以 return 一个 NSString
或 NSNull
所以它应该声明为 - (id) mobilePhone
。既然不是,我们可以扩展 MSGraphUser
extension MSGraphUser {
var optMobilePhone : String? { return self.dictionary["mobilePhone"] as? String }
}
然后使用计算得到的 属性 来安全地访问值:
for obj in users.value {
if let user = obj as? MSGraphUser {
print(user)
print(String(user.surname.dynamicType))
print(user.optMobilePhone ?? "no phone")
}
}
您可以使用一种方法来过滤空对象
- (NSString* __nullable) mobilePhone
{
if ([self.dictionary isKindOfClass:[NSString class]])
{
return self.dictionary[@"mobilePhone"];
}
return nil;
}
或
- (NSString* __nullable) mobilePhone
{
if (![self.dictionary isKindOfClass:[NSNull class]]) {
return self.dictionary[@"mobilePhone"];
}
return nil;
}
许多 JSON API 将 return 在 JSON 文档中为他们想要明确标记为不存在的值设置为空。这与根本不会报告的密钥不同。
您要做的第一件事是与 API 的创建者或文档核实应该如何解释这种值。例如,如果您请求键 "user",您可能会发现该值根本不存在、该值为空或该值为空字符串。找出每个值应该如何解释,或者它们是否应该被同等对待。
然后因为您将一直需要它,所以您向 NSDictionary 添加了一个函数,它将 return 您想要的内容,并记录您没有想到的内容。您通过检查 if let ... 来检查值是否根本不存在。你通过检查 value == NSNull () 来检查一个值是否为 null。然后你使该函数 return 成为可选字符串或字符串。
肯定会有更好的 swift 支持,但是现在,您可以像 Casey 所说的那样扩展 class。
如果你这样做了,你可以检查
if user.optMobilePhone is NSNull
实际的扩展看起来像这样:
extension MSGraphUser {
var optMobilePhone: AnyObject? {
return dictionaryFromItem()["mobilePhone"]
}
}
我正在尝试使用 Microsoft Graph iOS SDK and followed the official code sample。
以下代码片段用于获取组织中所有用户的基本资料:
private func getContactInfo(){
self.graphClient.users().request().getWithCompletion{
(collection: MSCollection?, request:MSGraphUsersCollectionRequest?, error: NSError?) in
if let users = collection {
for user: MSGraphUser in users.value as! [MSGraphUser] {
print(user)
print(String(user.surname.dynamicType))
print(user.mobilePhone)
}
}
}
}
输出结果:
{
businessPhones = (
);
displayName = "Boss";
givenName = "Jack";
id = "30fb78ff-522f-45e7-a9cd-75ba8ee2eca6";
jobTitle = "<null>";
mail = "boss@abc.net";
mobilePhone = "<null>";
officeLocation = "<null>";
preferredLanguage = "<null>";
surname = "\U8a79";
userPrincipalName = "boss@abc.net";
}
ImplicitlyUnwrappedOptional<String>
并且发生了运行时异常
2016-06-05 17:02:55.302 ABC[76976:915052] -[NSNull _fastCStringContents:]: unrecognized selector sent to instance 0xb59398
2016-06-05 17:02:55.305 ABC[76976:915052] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull _fastCStringContents:]: unrecognized selector sent to instance 0xb59398'
*** First throw call stack:
(
0 CoreFoundation 0x0092c494 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x02640e02 objc_exception_throw + 50
...
当我尝试像 mobilePhone 一样打印空值时,发生了运行时异常。如何检测空值以避免崩溃?谢谢。
添加:MSGraphUser.m片段在本例中使用,
@interface MSGraphUser()
{
...
NSString* _mobilePhone;
...
- (NSString*) mobilePhone
{
return self.dictionary[@"mobilePhone"];
}
...
看起来 mobilePhone
实际上可以 return 一个 NSString
或 NSNull
所以它应该声明为 - (id) mobilePhone
。既然不是,我们可以扩展 MSGraphUser
extension MSGraphUser {
var optMobilePhone : String? { return self.dictionary["mobilePhone"] as? String }
}
然后使用计算得到的 属性 来安全地访问值:
for obj in users.value {
if let user = obj as? MSGraphUser {
print(user)
print(String(user.surname.dynamicType))
print(user.optMobilePhone ?? "no phone")
}
}
您可以使用一种方法来过滤空对象
- (NSString* __nullable) mobilePhone
{
if ([self.dictionary isKindOfClass:[NSString class]])
{
return self.dictionary[@"mobilePhone"];
}
return nil;
}
或
- (NSString* __nullable) mobilePhone
{
if (![self.dictionary isKindOfClass:[NSNull class]]) {
return self.dictionary[@"mobilePhone"];
}
return nil;
}
许多 JSON API 将 return 在 JSON 文档中为他们想要明确标记为不存在的值设置为空。这与根本不会报告的密钥不同。
您要做的第一件事是与 API 的创建者或文档核实应该如何解释这种值。例如,如果您请求键 "user",您可能会发现该值根本不存在、该值为空或该值为空字符串。找出每个值应该如何解释,或者它们是否应该被同等对待。
然后因为您将一直需要它,所以您向 NSDictionary 添加了一个函数,它将 return 您想要的内容,并记录您没有想到的内容。您通过检查 if let ... 来检查值是否根本不存在。你通过检查 value == NSNull () 来检查一个值是否为 null。然后你使该函数 return 成为可选字符串或字符串。
肯定会有更好的 swift 支持,但是现在,您可以像 Casey 所说的那样扩展 class。
如果你这样做了,你可以检查
if user.optMobilePhone is NSNull
实际的扩展看起来像这样:
extension MSGraphUser {
var optMobilePhone: AnyObject? {
return dictionaryFromItem()["mobilePhone"]
}
}