Mor*_*ris 14 objective-c ios objective-c-blocks automatic-ref-counting
我正在尝试保留对通过方法传递给我的类的块的引用,以便稍后调用.然而,我遇到了麻烦,保持对它的引用.
我认为,显而易见的方法是将它添加到ivar集合中,所有这些集合都应该保持对其内容的强烈引用.但是当我试图将它拉回来时,它是零.
代码非常简单:
typedef void (^DataControllerCallback)(id rslt);
@interface DataController : NSObject {
NSMutableArray* queue;
}
- (void) addBlock:(DataControllerCallback)callback;
- (void) functionToBeCalledLater;
@end
@implementation DataController
- (id) init {
self = [super init];
if (self != nil) {
queue = [NSMutableArray new];
}
return self;
}
- (void) addBlock:(DataControllerCallback)callback {
NSDictionary* toAdd = [NSDictionary dictionaryWithObjectsAndKeys:
[callback copy], @"callback",
@"some other data", @"data", nil];
[queue addObject:toAdd];
}
- (void) functionToBeCalledLater {
NSDictionary* dict = [queue lastObject];
NSLog(@"%@", [dict objectForKey:@"data"]; //works
DataControllerCallback callback = [dict objectForKey:@"callback"]; //this is nil
callback(@"an arguemnt"); //EXC_BAD_ACCESS
}
Run Code Online (Sandbox Code Playgroud)
发生了什么?
更新:我已经尝试过[callback copy],只是callback插入字典,既不起作用.
更新2:如果我只是将我的块粘贴到NSMutableSet中,只要我打电话copy,我就没事了.它很棒.但如果它在NSDictionary中,则不然.
我实际上通过在创建NSDict之后放置一个断点并且永远不会插入回调来测试它.该描述清楚地读出"1键值对",而不是两个.
我现在用一个专门的类来解决这个问题,它只是一个容器.该callback财产被宣布为strong; 我甚至不需要使用copy.
但问题仍然存在:为什么会发生这种情况?为什么NSDictionary不会存储块?它是否与我瞄准iOS 4.3的事实有关,因此ARC必须作为静态库构建?
更新3:女士们,先生们:我是个白痴.
我在这里介绍的代码显然是实际代码的简化版本; 最特别的是,它将一些键/值对从字典中删除.
如果你存储一个值在一个NSDictionary使用[NSDictionary dictionaryWithObjectsAndKeys:],你最好是该死确保这些值的一个不是nil.
其中一个是.
ICYMI,它正在提前终止参数列表.我有一个userInfo类型参数被传递到"添加到队列"方法之一,当然,你可以传入"nil".然后,当我构造字典时,在该参数中查看导致构造函数认为我已经终止了参数列表.@"callback"是字典构造函数中的最后一个值,它从未被存储过.
bbu*_*bum 31
与流行的错误概念相反,ARC 不会自动对作为方法参数传递的块进行反堆叠.它仅在从方法/函数返回块时自动解除堆栈.
即这......
[dict setObject: ^{;} forKey: @"boom"];
Run Code Online (Sandbox Code Playgroud)
...如果dict幸存超出范围并且您尝试使用该块将崩溃(实际上,在这种情况下它不会因为这是一个静态块,但这是一个您不能依赖的编译器细节).
这在此处记录:
块如何在ARC中工作?
在ARC模式下向块传递块时块"正常工作",例如在返回中.您不必再调用Block Copy.将堆栈"向下"传递到
arrayWithObjects:其他执行保留的方法时,仍需要使用[^ {} copy] .
返回值行为可以自动化,因为返回基于堆的块总是正确的(并且总是返回基于堆栈的块的错误).在作为参数的块的情况下,不可能以非常有效且始终正确的方式自动化行为.
分析仪可能应该警告这种用途.如果没有,请提交错误.
(当我的意思是堆时,我把堆叠起来.对不起.)
由于以下几个原因,编译器不会自动执行block-as-parameters:
即:
doSomethingSynchronous(aBlock);
doSomethingSynchronous(aBlock);
doSomethingSynchronous(aBlock);
doSomethingSynchronous(aBlock);
Run Code Online (Sandbox Code Playgroud)
如果这意味着四个Block_copy()操作和aBlock包含大量捕获状态,那将是一个巨大的潜在打击.
•当天只有这么多小时,参数处理的自动化充满了非明显的边缘情况.如果将来自动处理,可以在不破坏现有代码的情况下完成,因此,将来可能会完成.
即编译器可以生成:
aBlock = [aBlock copy];
doSomethingSynchronous(aBlock);
doSomethingSynchronous(aBlock);
doSomethingSynchronous(aBlock);
doSomethingSynchronous(aBlock);
[aBlock release];
Run Code Online (Sandbox Code Playgroud)
这不仅会解决block-as-param的问题,而且还会在所有潜在用途中生成块的一个副本.
但问题仍然存在:为什么会发生这种情况?为什么NSDictionary不会存储块?它是否与我瞄准iOS 4.3的事实有关,因此ARC必须作为静态库构建?
那时奇怪的事情正在发生.巧合的是,我上周在基于ARC的应用程序中使用了块值作为值,并且它运行正常.
你有一个方便的小例子吗?
| 归档时间: |
|
| 查看次数: |
4425 次 |
| 最近记录: |