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

一 非ARC中的Block内存管理

1 先介绍内存的五大区:堆区;栈区;方法区;静态区(全局区);常量区
2 非ARC环境:
—-> 2.1 block在没有访问外部局部变量,存放在内存的全局区
—-> 具体代码演示:
- (void)viewDidLoad {
    [super viewDidLoad];

    void(^block)() = ^{

    };

    NSLog(@"%@",block);

    block();
}
—-> 打印不出来的结果显示:<NSGlobalBlock: 0x1071ba080>说明结论是对的
—->2.2 block访问外部局部变量,block存放栈区里面
—-> 具体代码演示:
- (void)viewDidLoad {
    [super viewDidLoad];
    int a = 10;
    void(^block)() = ^{
        NSLog(@"%d",a);

    };

    NSLog(@"%@",block);

    block();
}
—-> 打印出来的结果显示:<NSStackBlock: 0x7fff5a12f958>说明结论是对的
—-> 2.3 只要block访问变量,是整个app都存在的变量,那么肯定是在全局区
—-> 具体代码演示:
static int a = 10;
- (void)viewDidLoad {
    [super viewDidLoad];
    void(^block)() = ^{
        NSLog(@"%d",a);

    };

    NSLog(@"%@",block);

    block();
}
—-> 打印出来的结果显示:<NSGlobalBlock: 0x10beff080>说明结论是对的

二 非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();
}
—-> 打印显示的结果:<NSStackBlock: 0x7fff504f0960>说明结论是对的
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;
}
—-> 打印显示的结果:<NSMallocBlock: 0x7fd193da9800>说明结论是对的

五 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在内存当中的管理情况,或许介绍的还不是很完整,后期会跟进补充的,大家有什么意见,好的坏的可以给我留言,谢谢!!!!
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值