Understand one edge case of block memory management in objc

前端 未结 2 442
再見小時候
再見小時候 2021-01-03 11:50

the code below will crash because of EXC_BAD_ACCESS

typedef void(^myBlock)(void);

- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray *t         


        
2条回答
  •  北海茫月
    2021-01-03 11:57

    Short Answer:

    You have found a compiler bug, possibly a re-introduced one, and you should report it at http://bugreport.apple.com.

    Longer Answer:

    This wasn't always a bug, it used to be a feature ;-) When Apple first introduced blocks they also introduced an optimisation in how they implemented them; however unlike normal compiler optimisations which are essentially transparent to the code they required programmers to sprinkle calls to a special function, block_copy(), in various places to make the optimisation work.

    Over the years Apple removed the need for this, but only for programmers using ARC (though they could have done so for MRC users as well), and today the optimisation should be just that and programmers should no longer need to help the compiler along.

    But you've just found a case where the compiler gets it wrong.

    Technically you have a case a type loss, in this case where something known to be a block is passed as id - reducing the known type information, and in particular type loss involving the second or subsequent argument in a variable argument list. When you look at your array with po tmp you see the first value is correct, the compiler gets that one right despite there being type loss, but it fails on the next argument.

    The literal syntax for an array does not rely on variadic functions and the code produced is correct. However initWithObjects: does, and it goes wrong.

    Workaround:

    If you add a cast to id to the second (and any subsequent) blocks then the compiler produces the correct code:

    return [[NSArray alloc] initWithObjects:
            ^{NSLog(@"blk0:%d", val);},
            (id)^{NSLog(@"blk1:%d", val);},
            nil];
    

    This appears to be sufficient to wake the compiler up.

    HTH

提交回复
热议问题