您的位置:首页 > 其它

Block的深入研究之Block的内存管理

2016-03-31 02:39 260 查看

一 非ARC中的Block内存管理

1 先介绍内存的五大区:堆区;栈区;方法区;静态区(全局区);常量区

2 非ARC环境:

—-> 2.1 block在没有访问外部局部变量,存放在内存的全局区

—-> 具体代码演示:

- (void)viewDidLoad {
[super viewDidLoad];

void(^block)() = ^{

};

NSLog(@"%@",block);

block();
}


—-> 打印不出来的结果显示:<[b]NSGlobalBlock: 0x1071ba080>说明结论是对的[/b]

—->2.2 block访问外部局部变量,block存放栈区里面

—-> 具体代码演示:

- (void)viewDidLoad {
[super viewDidLoad];
int a = 10;
void(^block)() = ^{
NSLog(@"%d",a);

};

NSLog(@"%@",block);

block();
}


—-> 打印出来的结果显示:<[b]NSStackBlock: 0x7fff5a12f958>说明结论是对的[/b]

—-> 2.3 只要block访问变量,是整个app都存在的变量,那么肯定是在全局区

—-> 具体代码演示:

static int a = 10;
- (void)viewDidLoad {
[super viewDidLoad];
void(^block)() = ^{
NSLog(@"%d",a);

};

NSLog(@"%@",block);

block();
}


—-> 打印出来的结果显示:<[b]NSGlobalBlock: 0x10beff080>说明结论是对的[/b]

二 非ARC不能使用retain使用copy的原因

1 首先将定义block属性的copy修改为retain(会有警告,先不管)

@property (nonatomic, retain) void(^block)();


2 在没有调用block的时候,执行的block是在堆区

- (void)viewDidLoad {
[super viewDidLoad];
void(^block)() = ^{
NSLog(@"%@",block);

};

NSLog(@"%@",block);
self.block = block;

block();
}


—-> 打印显示的结果:<[b]NSStackBlock: 0x7fff504f0960>说明结论是对的[/b]

3 当点击屏幕调用block的时候就会报错

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.block();
}


—-> 错误原因:坏的内存访问

—-> 得出的结论:在非ARC当中,不能使用retain引用block,不会把block放在堆区中,在非ARC当中,只能使用copy,才能把block放入堆区中.

三 在非ARC开发当中注意点

1 访问属性,不要直接使用_,而是通过set,get方法去访问

2 非ARC中没有weak -> assign,strong -> retain

四 ARC环境的Block内存管理

—-> 结论:block访问外部局部变量,block存放在堆区里面.可以通过使用strong去引用.

—-> 实例验证结论

- (void)viewDidLoad {
[super viewDidLoad];

//block方法
int a = 4;
void(^block)() = ^{
NSLog(@"%d",a);

};
NSLog(@"%@",block);

block();

self.block = block;
}


—-> 打印显示的结果:<[b]NSMallocBlock: 0x7fd193da9800>说明结论是对的[/b]

五 Block的循环引用

1 Block简单的循环引用

注意点: block只要访问外部强指针对象变量,就会对这个变量进行强引用.

1.1 实例代码一:(点击控制器的view,model出一个控制器)

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//创建控制器对象
XFJModelViewController *model = [[XFJModelViewController alloc] init];

//设置颜色
model.view.backgroundColor = [UIColor redColor];

//model出来
[self presentViewController:model animated:YES completion:nil];
}


—> 问题一:控制器已过大括号会被销毁么?

—> 解答:不会.

—> 原因:presentViewController:该方法底层还会做一个事情,就是被presentedViewController强指针引用,再说了,如果出了大括号就会被销毁,那么我们在model出来的控制器中dissmis又怎么会有效果呢.所以model出来的控制器是不会被销毁的,知道dissmis的时候才销毁.(但是排除其它情况会让控制器销毁,我们离就不一一列举了)

1.2 实例代码块二:

—->1.2.1 定义一个在model出来的控制器中定义一个block属性,然后在viewDidLoad里面对block赋值

—->1.2.2 运行的结果是当点击控制器dissmiss的时候,控制器被销毁

[self dismissViewControllerAnimated:YES completion:nil];


—-> 1.2.3 控制器销毁的时候调用了dealloc方法.

1.3 实例代码块三:

- (void)viewDidLoad {
[super viewDidLoad];

int a = 6;

_block = ^{
NSLog(@"%@",self);
};

}


—> 1 在block块里面访问了self,强指针.

—> 2 得出的结论:model出来的控制器不会被销毁,因为没有调用dealloc方法.

画图解答疑问:



解决办法:将self变成弱指针.

具体实施方案:

__weak typeof(self) weakself = self;

_block = ^{
NSLog(@"%@",weakself);
};


2 复杂的block循环引用

注意:在开发当中我们有些时候,需要在block块中做一些延迟操作,但是我们很多时候无法保住对象的生命周期,往往我们还没有执行到延迟操作的时候,对象就被销毁了.

具体代码:

__weak typeof(self) weakself = self;
_block = ^{
//很多时候我们有可能在block块中做延迟操作,但是有可能我们会造成循环引用.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t) (2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//这里打印的结果为null,不能拿到控制器去做其它的事情.
NSLog(@"1----%@",weakself);

});

NSLog(@"2----%@",weakself);
};

_block();


—-> 1 打印的结果:

—-> 1.1 //2—-

—-> 1.2 //控制器被销毁了

—-> 1.3 //1—-(null)

—-> 2 这样就造成了,我们没发拿到对象去做延迟操作.

—-> 3 解决的思路:在言辞操作之前定义一个__strong,让对象运行完后保证不死.

代码块:

__weak typeof(self) weakself = self;
_block = ^{
__strong typeof(weakself) strongSelf = weakself;
//很多时候我们有可能在block块中做延迟操作,但是有可能我们会造成循环引用.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t) (2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//这里打印的结果为null,不能拿到控制器去做其它的事情.
NSLog(@"1----%@",strongSelf);

});

NSLog(@"2----%@",strongSelf);
};

_block();


—-> 1 打印结果:

—-> 1.1 //2—-

—-> 1.2 //1—-

—-> 1.3//控制器被销毁了

—-> 2 结论:这样做就能让对象在执行完延迟糙所的时候让对象销毁,达到了目的.

具体的图形解答疑惑:



六 总结

这里面介绍了大部分block运用会出现的情况,更多的还是block在内存当中的管理情况,或许介绍的还不是很完整,后期会跟进补充的,大家有什么意见,好的坏的可以给我留言,谢谢!!!!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: