【问题标题】:Remove NSNull values in a KVC generated NSMutableArray删除 KVC 生成的 NSMutableArray 中的 NSNull 值
【发布时间】:2015-02-16 17:40:12
【问题描述】:

这是一个小测试:

NSDictionary * test = @ { @"centers" : @[
                                         @{ @"id":@"12345", @"favorite":@NO },
                                         @{ @"id":@"2345", @"favorite":@NO },
                                         @{ @"id":@"345", @"favorite":@YES },
                                         @{ @"favorite":@NO }
                                         ]};

NSMutableArray * test2 = [test mutableArrayValueForKeyPath:@"centers.id"];
NSLog(@"%@",test2);

日志给出:

(
    12345,
    2345,
    345,
    "<null>"
)

太好了,现在,我希望摆脱 NSNull 值...根据How will I be able to remove [NSNull Null] objects from NSMutableArray?,这就是方式:

[test2 removeObjectIdenticalTo:[NSNull null]];
NSLog(@"%@",test2);

不幸的是,它崩溃了:

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSDictionaryI 0x7fe2ee01e970> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key id.'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010e47df35 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010e116bb7 objc_exception_throw + 45
    2   CoreFoundation                      0x000000010e47db79 -[NSException raise] + 9
    3   Foundation                          0x000000010dcb37b3 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 259
    4   Foundation                          0x000000010dd44be0 -[NSArray(NSKeyValueCoding) setValue:forKey:] + 186
    5   Foundation                          0x000000010dd471cc -[NSKeyValueSlowMutableArray removeObjectAtIndex:] + 89
    6   CoreFoundation                      0x000000010e3d75a3 -[NSMutableArray removeObjectIdenticalTo:] + 131
    7   TestImageSizeReduction              0x000000010dbe6d35 -[ViewController viewDidLoad] + 1397
    8   UIKit                               0x000000010ebd2a90 -[UIViewController loadViewIfRequired] + 738
    9   UIKit                               0x000000010ebd2c8e -[UIViewController view] + 27
    10  UIKit                               0x000000010eaf1ca9 -[UIWindow addRootViewControllerViewIfPossible] + 58
    11  UIKit                               0x000000010eaf2041 -[UIWindow _setHidden:forced:] + 247
    12  UIKit                               0x000000010eafe72c -[UIWindow makeKeyAndVisible] + 42
    13  UIKit                               0x000000010eaa9061 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 2628
    14  UIKit                               0x000000010eaabd2c -[UIApplication _runWithMainScene:transitionContext:completion:] + 1350
    15  UIKit                               0x000000010eaaabf2 -[UIApplication workspaceDidEndTransaction:] + 179
    16  FrontBoardServices                  0x0000000111f582a3 __31-[FBSSerialQueue performAsync:]_block_invoke + 16
    17  CoreFoundation                      0x000000010e3b353c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    18  CoreFoundation                      0x000000010e3a9285 __CFRunLoopDoBlocks + 341
    19  CoreFoundation                      0x000000010e3a9045 __CFRunLoopRun + 2389
    20  CoreFoundation                      0x000000010e3a8486 CFRunLoopRunSpecific + 470
    21  UIKit                               0x000000010eaaa669 -[UIApplication _run] + 413
    22  UIKit                               0x000000010eaad420 UIApplicationMain + 1282
    23  TestImageSizeReduction              0x000000010dbe81f3 main + 115
    24  libdyld.dylib                       0x0000000110c50145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

所以,我知道从数组中删除 NSNull 实例的许多方法(谓词、indexsPassingTests 等),但我真的很想了解为什么这会失败,但解释很少。

提前致谢。

编辑: 为了防止伊恩回答中给出的代理问题,最简单的解决方案是:

NSMutableArray * test2 = [[test valueForKeyPath:@"centers.id"] mutableCopy];

【问题讨论】:

  • 这是一个不可变的字典,因此您无法更改其中存储的内容。尝试将其更改为 NSMutableDictionary 并遍历所有键并删除等于 [NSNull null] 的键。
  • 感谢您的评论,但调用是在数组上,而不是在字典上,不是吗?
  • 试试我的答案应该可以。

标签: ios nsmutablearray key-value-coding kvc nsnull


【解决方案1】:

mutableArrayValueForKeyPath 返回的NSMutableArray 不是值的副本,而是一个代理可变数组,它在每次访问时查找原始对象。

告诉它删除对象将作用于您的原始对象。告诉它删除centers.id[NSNull null] 的对象会导致失败,因为这些对象不会响应id 的键值映射。奇怪的是,它一开始会给你任何结果,但你不能以你想要的方式使用这个 [NSNull null] 结果。

如果您只想要这些值并且您不希望任何可用于修改原始对象的操作,我建议您以不同的方式构造您的数组开始;也许有一个谓词。

【讨论】:

  • 感谢您的解释!它巧妙地解释了一切!太好了!
【解决方案2】:

NSNull 是一个 null 对象类型,它允许将 NULL 对象添加到数组,因为数组不接受 nil 值作为输入。如果有任何东西作为 NULL 我们必须输入数组,我们使用 [NSNull null] 单例类型对象。 在您的情况下,由于内存位置为空而生成它不是 [NSNull null] 对象类型。您不能使用 [test2 removeObjectIdenticalTo:[NSNull null]] 删除它;

可以使用 NSPredicate Search 删除

试试这个使用 NSPredicate Search 过滤 NSArray。您可以使用 NSPredicate 删除 null

NSDictionary * test = @ { @"centers" : @[
                                             @{ @"id":@"12345", @"favorite":@NO },
                                             @{ @"id":@"2345", @"favorite":@NO },
                                             @{ @"id":@"345", @"favorite":@YES },
                                             @{ @"favorite":@NO }
                                             ]};

    NSMutableArray * test2 = [test mutableArrayValueForKeyPath:@"centers.id"];
    NSLog(@"%@",test2);
    NSPredicate *predicate=[NSPredicate predicateWithFormat:@"SELF!=nil"];
    NSArray *test3=[test2 filteredArrayUsingPredicate:predicate];
    NSLog(@"%@",test3);

【讨论】:

  • 感谢您的回答,但我想了解为什么删除会崩溃,而不是如何防止它,正如我在问题中提到的那样。伊恩给出了很好的解释。
  • 我已经在我的回答中解释了为什么你不能从你的数组 test2 中删除 [NSNull null]
  • 其实对象是NSNull实例(枚举数组并记录每个类,你会看到),答案已经被Ian给出,并解释了。
  • 你是对的枚举对象是 NSNull 类型。我同意@Ian 的回答。
猜你喜欢
  • 1970-01-01
  • 2014-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-20
相关资源
最近更新 更多