0

在使用 解析来自 web 服务的 JSON 响应后NSJSONSerialization,我使用+isKindOfClass:来确保服务器返回我期望的数据类型。使用这种方法,我遇到了一些奇怪的行为,我将用一个例子来说明。

考虑以下对象:

// Definitions
NSDictionary *son = @{ @"firstname" : @"James", @"lastname" : @"Appleseed" };
NSDictionary *daughter = @{ @"firstname" : @"Susan", @"lastname" : @"Appleseed"};
NSArray *children = @[son, daughter];
NSDictionary *father = @{ @"firstname" : @"John", @"lastname" : @"Appleseed" };
NSDictionary *family = @{@"children" : children, @"father" : father};
NSDictionary *pedigree = @{@"family" : family };

这些对象代表从服务器返回的反序列化 JSON。现在,如果我想使用孩子的数组来计算使用 NSArray 的孩子有多少-count,我需要确保孩子对象是一个 NSArray。例如,如果子对象恰好是一个字符串,而应用程序需要一个数组,它会崩溃,因为字符串没有实现count方法。考虑以下实现所述检查的代码序列:

// First test
id _family = [pedigree objectForKey:@"family"];
if ([_family isKindOfClass:[NSDictionary class]])
{
    NSDictionary *_family = (NSDictionary *)_family;
    id _children = [_family objectForKey:@"children"];

    NSLog(@"Children: %@", _children);
    NSLog(@"Children classname: %@", NSStringFromClass(children.class));

    if ([_children isKindOfClass:[NSArray class]]) {
        NSLog(@"Children is an NSArray");
    } else {
        NSLog(@"Children is not an NSArray");
    }
} else {
    NSLog(@"Family is not an NSDictionary");
}

运行此代码后,控制台输出以下内容:

Children: (null)
Children classname: __NSArrayI
Children is not an NSArray

控制台输出看起来非常显着,甚至自相矛盾。当其类名是 __NSArrayI 时,children 怎么可能不是NSArray?

经过一番调试,我发现有两种方法可以解决这个问题:

  1. 删除此行NSDictionary *_family = (NSDictionary *)_family;
  2. _family使用与转换变量不同的名称

如何解释这种行为?

4

2 回答 2

2

在行

NSDictionary *_family = (NSDictionary *)_family;

您在当前范围内定义了一个新变量_family,这使得外部变量_family不可见。nil如果您使用 ARC 编译,Objective-C 指针将被初始化。

而且输出并不矛盾,因为你打印

NSStringFromClass(children.class);

这是children(不带下划线)的类,它是一个数组。但是_children(带下划线)是nil因为_familyis nil 如上所述。

实际上,如果您需要字典,则不需要类型转换。你可以做

NSDictionary *_family = [pedigree objectForKey:@"family"];
if ([_family isKindOfClass:[NSDictionary class]])
{
    NSArray *_children = [_family objectForKey:@"children"];

    if ([_children isKindOfClass:[NSArray class]]) {
        NSLog(@"Children is an NSArray");
    } else {
        NSLog(@"Children is not an NSArray");
    }
} else {
    NSLog(@"Family is not an NSDictionary");
}
于 2012-10-25T16:00:14.030 回答
0

您的变量children包含一个数组,您的变量_childrennil.

这解释了NSLog打印的第一个(null)(因为您 log _children,而不是children),但是NSLog打印的第二个__NSArrayI(因为您打印了children对象的类,而不是 nil_children变量的类。

你的第三个NSLog说它不是一个数组,因为你检查[_children isKindOfClass:...]并且_childrennil,所以[nil isKindOfClass:...]返回NO


所以要解决你的问题,你必须弄清楚为什么你的_children变量是nil(而你的children变量不是)。

这显然是因为您使用了一个_family隐藏其父级的变量。因此,该行NSDictionary *_family = (NSDictionary *)_family;显然使用了内部_family变量,并且具有与您编写的完全相同的行为NSDictionary *foo = (NSDictionary *)foo;:就像这样,将其转换foonil您想要的任何内容仍然会成功nil

为您的内部_family变量使用不同的名称以避免第二个_family变量隐藏外部_family变量,您的问题就会消失。id或者更好的是,完全删除这一行,因为在不强制转换的情况下调用方法没有问题(id实际上就是这样)

于 2012-10-25T16:15:31.323 回答