Pregunta

I am really confused with this one.

Here is my code:

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

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

inside of switch

... 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

When I run the code I see in logs:

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

So as you can see flock block should capture someId which is not the same inside different calls of the bounding function and then execute something depending on it. aBlock works as expected but flock always uses the same (the first) someId. I have also put a random number to double check and again as you see the first value is copied and used for both calls.

[downloader download:someUrl completionHandler:flock];

method copies flock to the object which has copy property of the same block type, then downloads resource and then executes saved block.

EDIT1 : If I pass block literal instead of making variable first

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

In debugger if I set breakpoint I can see that the block is _NSStackBlock_ and it has the same address(i.e. this is the same block literal) in different calls to bounding function. This means that I receive the same copy of the block as completion handler and therefore I print the same someId but in this case one question arises: Why do I receive the same stack block literal???

Could you please point me what is wrong with this code? Or why blocks behave like that in my case?

¿Fue útil?

Solución

"Why do I receive the same stack block literal?"

You don't.

Initially, the block is created on the stack. This "auto" variable ceases to exist when the method returns, no matter what. However, this stack block may/will be copied within download:completionHandler:. Due to the loop, it is very likely that a new stack block will get the same address - yet it isn't the same as the previous, since that one has been deallocated.

What you are seeing in the logs though, seems a bit strange. I too believe, you should see distinct values for someId.

In a simple test case, I couldn't reproduce your issue. I suspect there is an issue elsewhere.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top