NSDictionary 和 Objective-C 块怪癖 [英] NSDictionary and Objective-C block quirk

查看:66
本文介绍了NSDictionary 和 Objective-C 块怪癖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用键 NSString 和对象块初始化 NSDictionary,就像这样.

I initialise an NSDictionary with keys NSString and objects blocks, like so.

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

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

When I retrieve some of these blocks it fails on retrieval, ie

someVar = [d objectForKey:@"b"];

即使存在与 @"b" 关联的对象,也会失败.

fails even though there is an object associated with @"b".

当我记录字典时,我注意到我可以检索的对象存储为 __NSMallocBlock__ 而那些失败的存储为 __NSStackBlock__.尽管 __NSStackBlock__ 看起来有效,但调试器显示它包装了一个 nil 块.

When I log the dictionary I note that the objects I can retrieve are stored as __NSMallocBlock__ and those that fail are stored as __NSStackBlock__. Although the __NSStackBlock__ seems valid the debugger shows that it wraps a nil block.

编辑

这很疯狂,有两个原因.

This is crazy for two reasons.

首先,我无法仅使用上面的片段来生成错误.但是,如果该块还包含对任何弱指针的引用,则会导致错误.

First I am unable to generate the error using just the snippets above. However, if the block also contains a reference to any weak pointer, it does result in the error.

从而产生你需要的错误

__weak NSString * p = @"ab"; // Some weak pointer
NSDictionary * d =
[NSDictionary dictionaryWithObjectsAndKeys:
  ^ ( int p1 ){ some code }, @"a",
  ^ ( int p1, NSString * p2 ){ NSLog( @"%p", p ); }, @"b",
nil];

虽然之前给出的代码段没有任何问题.

while the snippet given earlier works without any trouble.

我已经尝试过使用弱指针指向 self 或指向上述任意字符串的失败代码段,但都失败了.请注意,即使指针无效,日志也应该可以正常工作.

I've tried the failing snippet with a weak pointer to self or to some arbitrary string as above and both fail. Note that even if the pointer is not valid that log should work without any issues.

其次,如上所述,当您检索对象时会发生错误!即使我什么都不做,只是从字典中检索它,我也会遇到 EXC_BAD_ACCESS 崩溃.

Secondly, as mentioned above, the error occurs when you retrieve the object! Even if I do nothing with the block, just retrieve it from the dictionary, I get a EXC_BAD_ACCESS crash.

推荐答案

唉,Apple 块处理中的另一个错误,我们以为他们已经在多年前修复了它们.

Sigh, yet another bug in Apple's block handling and we thought they'd fixed them all years ago.

首先在网站feedbackassistant.apple.com 上报告您的原始代码——他们修复它的可能性很小,但请无论如何都要这样做.(请随意包含以下代码作为正确处理的版本.)

First report your original code at the site feedbackassistant.apple.com – the chances that they'll fix it are slim but please do it anyway. (Feel free to include the code below as a version that is handled correctly.)

其次,您可以使用更现代的代码:

Second you can use more modern code:

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

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

which Apple does appear to compile correctly (and looking at the underling mechanisms and types it is possible to see why this is different from your code and doesn't have the same compiler bug).

后记

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

You are correct, Apple does store blocks differently depending on certain factors – this is a compiler optimisation and, like all such optimisations, should not be visible to the programmer accept in improved code (performance, size, etc.).

然而,由于苹果公司从未解释过的原因,他们决定发布这个优化的块实现对程序员可见,并且确实需要程序员添加特定的代码来处理它.随着时间的推移,他们不再需要添加该代码,并最终记录了工作完成".

However for reasons Apple never explained they decided to release the block implementation with this optimisation visible to the programmer, and indeed required the programmer to add specific code to deal with it. Over time they made adding that code unnecessary and finally documented "job done".

在同样使用 ARC 的 Swift 中,他们似乎已经从使用 Objective-C 的经验中吸取了教训,并通过优化和语言级注释的组合正确实现了块处理——人们可能会就必要性/好处/成本/选择/等.后者,但我们可以说 Apple 在做出选择方面并不是独一无二的,与他们从 Objective-C 中的块开始相比,这无疑是一个巨大的改进.

In Swift, which also uses ARC, they seem to have learnt from their experience with Objective-C and implemented block handling correctly through a combination of optimisations and language-level annotations – one could have a debate over the necessity/benefit/cost/choice/etc. of the latter but we can say Apple isn't unique in making the choice and it is certainly a massive improvement over where they started with blocks in Objective-C.

这篇关于NSDictionary 和 Objective-C 块怪癖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆