关于OC中的Block使用以及ARC和MAR下的内存管理方式

1.什么是Block?

    Block是属于C语言框架

    Block是一种数据类型(类似int)

    Block是一段代码块,只有在被调用的时候被执行(类似函数和方法)

    Block可以定义成临时变量

    Block可以定义成参数

    Block可以定义成属性

2.Block的语法结构 

1.无参数,无返回值

 
 
  1. /*
  2.     数据类型 : void(^)()
  3.     变量名   : task1
  4.     值       : ^{ NSLog(@"task1"); };
  5.     */
  6.    void(^task1)() = ^{
  7.        NSLog(@"task1");
  8.    };

2.有参数,无返回值

 
 
  1. //    参数类型(如果有形参,这个可省)    形参
  2.    void(^task2)(NSString *) = ^(NSString *str){
  3.        NSLog(@"task2 %@",str);
  4.    };

3.无参数,有返回值

 
 
  1. int(^task3)() = ^{
  2.        return 1;
  3.    };

4.有参数,有返回值

 

 
 
  1. int(^task4)() = ^(int a,int b){
  2.        return a + b;
  3.    };

3.ARC下,Block的内存空间

结论:

 1.ARC环境下,单纯的定义一个block存储在全局区 <__NSGlobalBlock__: 0x1045c60b0>

示例代码

 
 
  1. - (void)blockDemo
  2. {
  3.    void(^task1)() = ^{
  4.        NSLog(@"task");
  5.    };
  6.    task1();
  7.    // block的本质是指针对象
  8.    // ARC环境下,单纯的定义一个block存储在全局/常量区 <__NSGlobalBlock__: 0x10e80f100>
  9.    NSLog(@"task1==%@",task1);
  10. }

控制台打印:

 
 
  1. 2016-06-27 08:55:51.263 Block使用[732:22600] task
  2. 2016-06-27 08:55:51.264 Block使用[732:22600] task1==<__NSGlobalBlock__: 0x10e80f100>

4.ARC下,Block内访问外部变量的内存变化

结论:

前提是ARC : Block访问外部的变量

 2.ARC环境下,block访问外部的变量时存储在堆区 <__NSMallocBlock__: 0x7fa8fd00c1b0>

     2.1 block访问这个变量之前,变量在栈区 == 0x7fff53c73bfc

     2.2 block内部访问这个变量时,变量会被block拷贝到堆区 0x7fe851517880

示例代码:

 
 
  1. #pragma mark - ARC - Block访问外部的变量
  2. // 需求 : 研究block和外部变量的内存的变化
  3. - (void)blockDemo1
  4. {
  5.    int num = 10;
  6.    // 在block访问这个变量之前,变量在栈区 == 0x7fff52544bec
  7.    NSLog(@"num01==%p",&num);
  8.    void(^task1)() = ^{
  9.        // 在block内部访问这个变量时,变量会被block拷贝到堆区 0x7f8108e0d620
  10.        NSLog(@"task1 %d %p",num,&num);
  11.    };
  12.    task1();
  13.    // block的本质是指针对象
  14.    // ARC环境下,block访问外部的变量时存储在堆区 <__NSMallocBlock__: 0x7f8108e0d600>
  15.    NSLog(@"task1==%@",task1);
  16.    
  17.    // 当block在其内部使用完了外部的变量之后,这个变量又会重新回到栈区 0x7fff52544bec
  18.    NSLog(@"num02==%p",&num);
  19. }

控制台打印日志:

 
 
  1. 2016-06-27 08:59:39.334 Block使用[753:25411] num01==0x7fff52544bec
  2. 2016-06-27 08:59:39.334 Block使用[753:25411] task1 10 0x7f8108e0d620
  3. 2016-06-27 08:59:39.334 Block使用[753:25411] task1==<__NSMallocBlock__: 0x7f8108e0d600>
  4. 2016-06-27 08:59:39.334 Block使用[753:25411] num02==0x7fff52544bec

5.ARC下,Block内修改外部变量的内存变化

结论:

前提是ARC : Block修改外部的变量

 1.ARC环境下,block修改外部变量的时候,会在堆区 <__NSMallocBlock__: 0x7f82ac8a6130>

 2.block的外面,即使你使用__block修饰了,那么他的地址依然不变,在栈区 0x7fff5e101bf8

 3.block内部修改外部的变量时,使用__block修饰了外部的变量之后,外部的变量会在堆区0x7f9d10e0bcc8

示例代码

 
 
  1. #pragma mark - ARC - Block修改外部的变量
  2. // 需求 : 研究block和外部变量的内存的变化
  3. - (void)blockDemo2
  4. {
  5.    __block int num = 10;
  6.    // 在block的外面,即使你使用__block修饰了,那么他的地址依然不变,在栈区 0x7fff57337be8
  7.    NSLog(@"num01==%p",&num);
  8.    void(^task2)() = ^{
  9.        /*
  10.         提示 : 在block内部修改外部变量是不被允许的
  11.         如果非要修改,那么久需要把外部的变量用 __block 来修饰
  12.         */
  13.        num = 20;
  14.        // 在block内部修改外部的变量时,使用__block修饰了外部的变量之后,外部的变量会在堆区 0x7fd3ea443ad8
  15.        NSLog(@"task2 %d =%p",num,&num);
  16.    };
  17.    task2();    
  18.    // 当block修改外部变量的时候,会在堆区 <__NSMallocBlock__: 0x7fd3ea438d70>
  19.    NSLog(@"task2%@",task2);    
  20.    // 当block内部修改完外部的变量之后,那么这个变量的就会保存到堆区 0x7fd3ea443ad8
  21.    NSLog(@"num02==%p",&num);
  22. }

控制台打印日志

 
 
  1. 2016-06-27 09:04:17.459 Block使用[773:28467] num01==0x7fff57337be8
  2. 2016-06-27 09:04:17.460 Block使用[773:28467] task2 20 =0x7fd3ea443ad8
  3. 2016-06-27 09:04:17.460 Block使用[773:28467] task2<__NSMallocBlock__: 0x7fd3ea438d70>
  4. 2016-06-27 09:04:17.460 Block使用[773:28467] num02==0x7fd3ea443ad8

6.MRC下,Block的内存位置

结论:

 1.MRC环境下,单纯的定义一个block存储在全局区 <__NSGlobalBlock__: 0x1045c60b0>

示例代码

 
 
  1. - (void)blockDemo1
  2. {
  3.    void(^task1)() = ^{
  4.    };
  5.    
  6.    task1();
  7.    
  8.    // 全局/常量区 <__NSGlobalBlock__: 0x10ddf10f0>
  9.    NSLog(@"%@",task1);
  10. }

控制台信息

 
 
  1. 2016-06-27 09:42:17.813 MRC下Block内存管理[973:45271] <__NSGlobalBlock__: 0x10ddf10f0>


7.MRC下,Block的访问外部变量的内存变化

结论:

 1.MRC环境下,Block访问外部变量的时候存放在栈区。 <__NSStackBlock__: 0x7fff58e23b08>

    a.Block访问外部变量时,外部变量在栈区,地址 0x7fff58e23b3c

    b.Block访问外部变量时,外部变量依然在栈区,但是地址发生了变化  0x7fff58e23b28

    c.Block访问结束以后。外部变量依然在栈区,并且地址和原始的一致。

示例代码

 
 
  1. - (void)blockDemo2
  2. {
  3.    int num = 10;
  4.    
  5.    // 变量的内存在栈区 0x7fff58e23b3c
  6.    NSLog(@"num01==%p",&num);
  7.    
  8.    void(^task2)() = ^{
  9.        
  10.        // 外部的变量在block内部依然在栈区,但是地址变了 0x7fff58e23b28 (地址变化了,内存空间没变)
  11.        NSLog(@"task2 %d %p",num,&num);
  12.    };
  13.    task2();
  14.    
  15.    // block存储在栈区 <__NSStackBlock__: 0x7fff58e23b08>
  16.    NSLog(@"%@",task2);
  17.    
  18.    // 变量依然在栈区,并且地址和开始时的一样 0x7fff58e23b3c
  19.    NSLog(@"num02==%p",&num);
  20. }

控制台信息

 
 
  1. 2016-06-27 09:47:52.118 MRC下Block内存管理[987:48208] num01==0x7fff58e23b3c
  2. 2016-06-27 09:47:52.119 MRC下Block内存管理[987:48208] task2 10 0x7fff58e23b28
  3. 2016-06-27 09:47:52.119 MRC下Block内存管理[987:48208] <__NSStackBlock__: 0x7fff58e23b08>
  4. 2016-06-27 09:47:52.119 MRC下Block内存管理[987:48208] num02==0x7fff58e23b3c

8.MRC下,Block修改外部变量的内存变化

结论:

1.MRC环境下,Block修改外部变量时存放在栈区<__NSStackBlock__: 0x7fff57e2cae0>

     a.Block修改外部变量前,外部变量存放在栈区 

     b.Block修改外部变量时,外部变量依然存放在栈区,但是地址发生了变化。

     c.Block修改外部变量之后,外部变量的地址已经发生变化,已经不是原始值了。

示例代码

 
 
  1. - (void)blockDemo3
  2. {
  3.    __block int num = 10;
  4.    
  5.    // 在block访问之前,外部变量存放在栈区 0x7fff57e2cb38
  6.    NSLog(@"num01==%p",&num);
  7.    
  8.    void (^task3)() = ^{
  9.        
  10.        num = 20;
  11.        
  12.        //在block修改时,外部变量依然存放在栈区,但是地址发生了变化, 0x7fff57e2cb38
  13.        NSLog(@"task3 %d %p",num,&num);
  14.    };
  15.    
  16.    task3();
  17.    
  18.    // block的地址存放在栈区  <__NSStackBlock__: 0x7fff57e2cae0>
  19.    NSLog(@"%@",task3);
  20.    
  21.    // 外部变量在block内部修改以后,地址为修改时的地址,依然存放在栈区 0x7fff57e2cb38
  22.    NSLog(@"num02==%p",&num);
  23. }

控制台信息

 
 
  1. 2016-06-27 10:00:01.069 MRC下Block内存管理[1006:53704] num01==0x7fff57e2cb38
  2. 2016-06-27 10:00:01.069 MRC下Block内存管理[1006:53704] task3 20 0x7fff57e2cb38
  3. 2016-06-27 10:00:01.069 MRC下Block内存管理[1006:53704] <__NSStackBlock__: 0x7fff57e2cae0>
  4. 2016-06-27 10:00:01.070 MRC下Block内存管理[1006:53704] num02==0x7fff57e2cb38


8.为什么Block属性需要使用copy修饰

        a.在ARC下,使用strong和copy都是一样的,因为在访问/修改外部变量的时候,block都是在堆区,苹果官方建议使用copy

        b.在MRC下,单纯的Block是存放在全局/常量区的,如果Block访问/修改外部变量后,block存放在了栈区,在栈区是不可以全局共享的,只有堆区的对象,变量才会被全局共享,所以使用copy拷贝一份Block到堆区中,这样Block才会全局共享。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值