NSDictionary and Objective-C block quirk

问题描述 投票:0回答:2

我像这样用键NSString和对象块初始化NSDictionary。

NSDictionary * d =
[NSDictionary dictionaryWithObjectsAndKeys:
  ^ ( int p1 ){ some code }, @"a",
  ^ ( int p1, NSString * p2 ){ some code }, @"b",
nil];

当我检索其中一些块时,它会失败[[检索时,即

someVar = [d objectForKey:@"b"];
即使有与@"b"相关联的对象也失败。

[登录字典时,我注意到可以检索的对象存储为__NSMallocBlock__,失败的对象存储为__NSStackBlock__。尽管__NSStackBlock__似乎有效,但调试器显示它包装了nil块。

objective-c objective-c-blocks
2个回答
0
投票
这与块参数有关。

编译器和ARC根据块的参数以不同的方式存储块。要解决此问题,请创建指向块的强指针,然后将这些指针存储在字典中,因此

blockVarA = ^ ( pars ){ some code }; // Strong pointers blockVarB = ^ ( pars ){ some code }; NSDictionary * d = [NSDictionary dictionaryWithObjectsAndKeys: blockVarA, @"a", blockVarB, @"b", nil];

将确保全部都存储为__NSMallocBlock__块。    

0
投票
抱歉,Apple块处理中的另一个错误,我们认为他们已经在整年前修复了它们。

首先在网站feedbackassistant.apple.com上报告您的原始代码-他们将对其进行修复的可能性很小,但无论如何请这样做。 (请随意将下面的代码作为可以正确处理的版本。)

第二,您可以使用更现代的代码:

NSDictionary * d = @{ @"a" : ^ ( int p1 ){ NSLog(@"%d", p1 * arg); }, @"b" : ^ ( int p1, NSString * p2 ){ NSLog(@"%d, '%@'" };

Apple看起来确实可以正确编译(并且查看底层的机制和类型,可以看到为什么这与您的代码不同并且没有相同的编译器错误)。

Postscript] >>[您是正确的,Apple确实会根据某些因素以不同的方式存储块-这是编译器优化,与所有此类优化一样,程序员在改进的代码(性能,大小等)中不应该看到它们。

但是出于种种原因,Apple从未解释过,他们决定发布这种对程序员可见的优化实现,并确实要求程序员添加特定的代码来对其进行处理。随着时间的流逝,他们使添加该代码成为不必要,并最终记录为“工作完成”。

[在还使用ARC的Swift中,他们似乎是从Objective-C的经验中学到的,并通过优化和语言级别的注释的组合正确地实现了块处理-有人可能会就必要性/益处/成本进行辩论/ choice / etc。后者,但是我们可以说Apple在做出选择方面并不是唯一的,并且在他们从Objective-C中的块开始的位置上肯定是一个巨大的进步。

© www.soinside.com 2019 - 2024. All rights reserved.