为什么ObjC块在捕获变量时释放,而不是在它没有时释放?

时间:2013-05-18 09:28:35

标签: objective-c objective-c-blocks weak-references

示例:

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;
}

输出是:

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]: ##############

并崩溃:)

将块分配给__weak blk变量后,它在autoreleasepool中注册,因此在离开范围后它不应该等于nil,但确实如此!为什么呢?

从blk捕获变量“a”后,我有以下输出:

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!

没有任何崩溃。

1 个答案:

答案 0 :(得分:3)

知道了!

使用没有捕获变量的块,它被添加到_NSGlobalBlock内存段,因此它的内存地址始终有效,但是当块捕获变量“a”时,它被添加到_NSStackBlock内存段,并在离开作用域后释放它。

要使用捕获的变量,我们应该使用copy方法,并且该块将被移动到_NSMallocBlock内存段。

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;
}

输出:

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