1

Example:

extern void _objc_autoreleasePoolPrint();

int main(int argc, char *argv[])
{

    @autoreleasepool {

        id __weak blk;

        {
            int a = 10;

            blk = ^(NSString *msg){
                NSLog(@"msg: %@", msg);
                NSLog(@"%d", a);
            };
        }

        NSLog(@"blk: %@", blk);

        _objc_autoreleasePoolPrint();

        ((void (^)(NSString *))blk)(@"Hello!");

    }

    return 0;
}

Output is:

2013-05-18 13:24:10.355 __iOS_SimpleConsoleApplication[63449:c07] blk: (null)
objc[63449]: ##############
objc[63449]: AUTORELEASE POOLS for thread 0xac583a28
objc[63449]: 1 releases pending.
objc[63449]: [0x7a73000]  ................  PAGE  (hot) (cold)
objc[63449]: [0x7a73028]  ################  POOL 0x7a73028
objc[63449]: ##############

and crash :)

After assigning block to __weak blk variable it's registered in autoreleasepool, so after leaving the scope it should not be equal to nil, but it does! Why?

After removing variable "a" from being captured by blk I have following output:

2013-05-18 13:25:34.132 __iOS_SimpleConsoleApplication[63486:c07] blk: <__NSGlobalBlock__: 0x35d0>
objc[63486]: ##############
objc[63486]: AUTORELEASE POOLS for thread 0xac583a28
objc[63486]: 2 releases pending.
objc[63486]: [0x7923000]  ................  PAGE  (hot) (cold)
objc[63486]: [0x7923028]  ################  POOL 0x7923028
objc[63486]: [0x792302c]            0x35d0  __NSGlobalBlock__
objc[63486]: ##############
2013-05-18 13:25:34.142 __iOS_SimpleConsoleApplication[63486:c07] msg: Hello!

without any crash.

AndrewShmig
  • 4,843
  • 6
  • 39
  • 68

1 Answers1

3

Got it!

Using block without captured variable it is being added to _NSGlobalBlock memory segment, so its memory address is always valid, but when block captures variable "a" its being added to _NSStackBlock memory segment and after leaving scope its being released.

To use captured variable we should use copy method and the block will be moved to _NSMallocBlock memory segment.

extern void _objc_autoreleasePoolPrint();

int main(int argc, char *argv[])
{

    @autoreleasepool {

        id blk;

        {
            int a = 10;

            blk = [^(NSString *msg){
                NSLog(@"msg: %@", msg);
                NSLog(@"a: %d", a);
            } copy];

        }

        NSLog(@"blk: %@", blk);

        _objc_autoreleasePoolPrint();

        ((void (^)(NSString *))blk)(@"Hello!");

    }

    return 0;
}

Output:

2013-05-18 13:43:51.947 __iOS_SimpleConsoleApplication[63822:c07] blk: <__NSMallocBlock__: 0x7190120>
objc[63822]: ##############
objc[63822]: AUTORELEASE POOLS for thread 0xac583a28
objc[63822]: 1 releases pending.
objc[63822]: [0x7b9f000]  ................  PAGE  (hot) (cold)
objc[63822]: [0x7b9f028]  ################  POOL 0x7b9f028
objc[63822]: ##############
2013-05-18 13:43:51.952 __iOS_SimpleConsoleApplication[63822:c07] msg: Hello!
2013-05-18 13:43:51.952 __iOS_SimpleConsoleApplication[63822:c07] a: 10
AndrewShmig
  • 4,843
  • 6
  • 39
  • 68