Objective-C块。 Context捕获相同的变量/复制相同的NSStackBlock

时间:2014-03-31 15:51:30

标签: ios iphone objective-c objective-c-blocks

我真的很困惑这个。

这是我的代码:

for (SomeObject *obj in objects) {
    [self checkAndDownloadForObject:obj];
}

- (void)checkAndDownloadForObject:(id)obj
{
    switch (obj.type) {

开关里面

... switch case scope

NSString *someId = [object.ID copy];    
NSInteger random = arc4random();
NSLog(@"working on id=%@", someId);

void (^flock)(NSData *data, NSError *error) = ^(NSData *data, NSError *error) {
    NSLog(@"downloaded image for %@ image =%p", someId, data);
    NSLog(@"random = %u", random);
    [self useDataForId:someId withData:data];                   
};

NSLog(@"flock %@", flock);

[downloader download:someUrl completionHandler:flock];

void (^aBlock)(int rand) = ^(int rand){
    NSLog(@"block ra =%d random %u someId %@", rand, random, someId);
};

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    int ra = arc4random();
    aBlock(ra);
});

// end of switch case scope

当我运行我在日志中看到的代码时:

2014-03-31 17:05:10.741 App[4142:60b] working on id=v7GhDlrq
2014-03-31 17:05:10.742 App[4142:60b] flock <__NSMallocBlock__: 0x17e86e00>
2014-03-31 17:05:10.787 App[4142:60b] working on id=tns_7Z-I
2014-03-31 17:05:10.788 App[4142:60b] flock <__NSMallocBlock__: 0x17ec85c0>
2014-03-31 17:05:10.824 App[4142:60b] downloaded image for v7GhDlrq image =0x18528a00
2014-03-31 17:05:10.825 App[4142:60b] random = 3993203783
2014-03-31 17:05:10.830 App[4142:60b] downloaded image for v7GhDlrq image =0x1852cc00
2014-03-31 17:05:10.831 App[4142:60b] random = 3993203783
2014-03-31 17:05:11.885 App[4142:60b] block ra =-2048013895 random 3993203783 someId v7GhDlrq
2014-03-31 17:05:11.886 App[4142:60b] block ra =513751079 random 727217709 someId tns_7Z-I

因为你可以看到flock块应该捕获someId,它在绑定函数的不同调用中是不同的,然后根据它执行某些操作。 aBlock按预期工作,但flock始终使用相同的(第一个)someId。我还给一个随机数进行了仔细检查,然后再次看到第一个值被复制并用于两个调用。

[downloader download:someUrl completionHandler:flock];

方法将flock复制到具有相同块类型的copy属性的对象,然后下载资源然后执行已保存的块。

EDIT1: 如果我传递块文字而不是先变量

 [downloader download:someUrl completionHandler:^{
      ...block
 }];

在调试器中,如果我设置了断点,我可以看到该块是 _ NSStackBlock _ ,并且它具有相同的地址(即,这是相同的块文字)调用边界函数。这意味着我收到了与完成处理程序相同的块副本,因此我打印相同的someId,但在这种情况下出现了一个问题:为什么我会收到相同的堆栈块文字???

请指点我这个代码有什么问题?或者为什么块在我的情况下表现得像那样?

1 个答案:

答案 0 :(得分:2)

  

&#34;为什么我会收到相同的堆栈块文字?&#34;

你不是。

最初,在堆栈上创建块。这个&#34; auto&#34;无论如何,方法返回时变量都不存在。但是,此堆栈块可能/将在download:completionHandler:内复制。由于循环,新堆栈块很可能会获得相同的地址 - 但它与之前的地址不同,因为那个已被解除分配。

你在日志中看到的,看起来有点奇怪。我也相信,你应该看到someId的不同值。

在一个简单的测试案例中,我无法重现您的问题。我怀疑其他地方有问题。