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 一个 NSStringNSNull 所以它应该声明为 - (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"]
   }
}