gpt4 book ai didi

objective-c - Block 在 NSDictionary (ARC) 中被释放

转载 作者:技术小花猫 更新时间:2023-10-29 10:14:05 26 4
gpt4 key购买 nike

我试图保留对通过方法传递到我的类的 Block 的引用,以便稍后调用。但是,我在维护对它的引用时遇到了麻烦。

我想,最明显的方法是将它添加到一个 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
}

发生了什么事?


更新:我已经用[callback copy] 尝试过,只是callback 插入到字典中,都不起作用。


更新 2:如果我只是将 block 插入 NSMutableSet,只要调用 copy,就可以了。它很好用。但如果它在 NSDictionary 中,则不会。

我实际上已经通过在创建 NSDict 之后放置一个断点来测试它,并且永远不会插入回调。描述清楚地写着“1 个键值对”,而不是两个。

我目前正在使用一个专门充当容器的类来解决这个问题。 callback 属性声明为 strong;我什至不需要使用 copy

但问题仍然存在:为什么会发生这种情况?为什么 NSDictionary 不存储 block ?这与我的目标是 iOS 4.3 并且因此必须将 ARC 构建为静态库这一事实有关吗?


更新 3:女士们先生们:我是个白痴。

我在这里展示的代码显然是实际代码的简化版本;最特别的是,它从字典中遗漏了一些键/值对。

如果您使用 [NSDictionary dictionaryWithObjectsAndKeys:] 在 NSDictionary 中存储一个,您最好damn确定其中之一值不是 nil

其中之一是。

ICYMI,它导致参数列表提前终止。我有一个 userInfo 类型的参数被传递到“添加到队列”方法之一,你当然可以传递“nil”。然后,当我构造字典时,插入该参数导致构造函数认为我已经终止了参数列表。 @"callback" 是字典构造函数中的最后一个值,它从未被存储。

最佳答案

与流行的误解相反,ARC 不会自动取消堆叠作为参数传递给方法的 block 。它仅在从方法/函数返回 block 时自动取消堆栈。

即这....

[dict setObject: ^{;} forKey: @"boom"];

... 如果 dict 在范围之外存活并且您尝试使用该 block (实际上,在这种情况下不会,因为它是一个静态 block ,但它是一个编译器),将会崩溃您不能依赖的细节)。

这是 documented here :

How do blocks work in ARC?

Blocks “just work” when you pass blocks up the stack in ARC mode, such as in a return. You don’t have to call Block Copy any more. You still need to use [^{} copy] when passing “down” the stack into arrayWithObjects: and other methods that do a retain.

返回值行为可以自动化,因为返回基于堆的 block 总是是正确的(返回基于堆栈的 block 总是错误的)。在 block 作为参数的情况下,不可能以一种既非常有效又始终正确的方式自动化行为。

分析器可能应该警告这种用途。如果没有,请提交错误。

(当我指的是时,我删除了一个堆栈。对此感到抱歉。)


出于以下几个原因,编译器不会自动将 block 作为参数:

  • 不必要地将 block 复制到堆中可能会严重影响性能
  • block 的多个副本可以显着增加性能损失。

即:

 doSomethingSynchronous(aBlock);
doSomethingSynchronous(aBlock);
doSomethingSynchronous(aBlock);
doSomethingSynchronous(aBlock);

如果这意味着四个 Block_copy() 操作并且 aBlock 包含大量捕获的状态,那将是一个巨大的潜在打击。

• 一天只有这么多小时,参数的自动化处理充斥着不明显的边缘情况。如果将来可以自动处理,则可以在不破坏现有代码的情况下完成,因此,将来可能会完成。

即编译器可以生成:

 aBlock = [aBlock copy];
doSomethingSynchronous(aBlock);
doSomethingSynchronous(aBlock);
doSomethingSynchronous(aBlock);
doSomethingSynchronous(aBlock);
[aBlock release];

这不仅会解决 block 作为参数的问题,而且它还会在所有潜在用途中只生成一个 block 副本。


The question still stands, though: why is this happening? Why won't an NSDictionary store a Block? Does it have something to do with the fact that I'm targeting iOS 4.3 and thus ARC must be built in as a static library?

然后,奇怪的事情发生了。巧合的是,上周我一直在基于 ARC 的应用程序中使用 block 作为值,并且运行良好。

你有一个简单的例子吗?

关于objective-c - Block 在 NSDictionary (ARC) 中被释放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8089896/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com