程序员

block-对象类型的auto变量

2018-07-03  本文已影响30人  RM_乾笙

从上些章节block-变量的捕获(caputer)中,详细说了基本类型的auto变量的捕获,现在来了解下,对象类型的auto变量是怎样捕获和底层结构是如何的。

block自动copy的情况

在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如以下情况


#import <Foundation/Foundation.h>
#import "RMPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...        
        RMPerson *person = [[RMPerson alloc] init];
        person.age = 20;
        
        void (^block)(void) = ^ {
            NSLog(@"age is %d",person.age);
        };

        [person release];
        NSLog(@"-----------");
    }
    return 0;
}

----------------- RMPerson.h -----------------
#import <Foundation/Foundation.h>
@interface RMPerson : NSObject
@property (nonatomic, assign) int age;
@end

----------------- RMPerson.m -----------------
#import "RMPerson.h"
@implementation RMPerson
- (void)dealloc {
    [super delloc];
    NSLog(@"RMPerson-delloc");
}
@end


// MRC 环境 控制台输出 
2018-07-03 10:34:39.523223+0800 __block的本质[20912:1898201] RMPerson-delloc
2018-07-03 10:36:17.021712+0800 __block的本质[20912:1898201] -----------
Program ended with exit code: 0

留意上面代码,是在MRC的环境下的代码,当NSLog(@"-----------");打印前了,RMPerson就释放了,什么原因呢?虽然block访问的是对象类型的auto变量,但还是访问了auto变量,所以block是属于NSStackBlock,是存在栈空间的,block运行完就会释放,它自己都不知道自己能存活多久,所以是不会作强持有RMPerson的操作。(结论一:如果block是在栈上,将不会对auto变量产生强引用)


#import <Foundation/Foundation.h>
#import "RMPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...        
        RMPerson *person = [[RMPerson alloc] init];
        person.age = 20;
        
        void (^block)(void) = [^ {
            NSLog(@"age is %d",person.age);
        } copy]; // copy操作,从栈中复制到堆中

        [person release];
        NSLog(@"-----------");
    }
    return 0;
}

----------------- RMPerson.h -----------------
#import <Foundation/Foundation.h>
@interface RMPerson : NSObject
@property (nonatomic, assign) int age;
@end

----------------- RMPerson.m -----------------
#import "RMPerson.h"
@implementation RMPerson
- (void)dealloc {
    [super delloc];
    NSLog(@"RMPerson-delloc");
}
@end


// MRC 环境 控制台输出 
2018-07-03 10:49:35.425698+0800 __block的本质[21020:1916302] -----------
Program ended with exit code: 0

从上面的控制台输出可以看出,即使程序结束了,RMPerson都没有释放,这是为什么呢? 因为block做了copy操作,从栈中拷贝到了堆中,此时block强引用了RMPerson,所以保住了RMPerson。
下面我们来看一下,底层c++代码是如何堆中的block是如何保住RMPerson的。


对象类型的auto变量

从上面源码分析,

如果block被拷贝到堆上时
如果block从堆上移除
block copy

总结:

当block内部访问了对象类型的auto变量时

1.如果block是在栈上,将不会对auto变量产生强引用

2.如果block被拷贝到堆上

3.如果block从堆上移除

上一篇 下一篇

猜你喜欢

热点阅读