美文网首页
__block修饰符(四)

__block修饰符(四)

作者: 鄂北 | 来源:发表于2021-09-03 15:58 被阅读0次

一、不加__block修饰符的情况下在block内部修改变量

1、基本数据类型的auto局部变量

1-1.png

在block中无法修改基本数据类型的auto局部变量,修改时会报Variable is not assignable (missing __block type specifier)错误。block对基本数据类型的auto局部变量是值捕获,无法去修改外部的变量。

2、static修饰的基本数据类型局部变量

1-2.png
如果是static修饰的基本数据类型局部变量,在block内部就能修改外部的变量。block对static修饰的基本数据类型局部变量是指针捕获,在block内部可以修改外部变量而不报错。

3、全局变量
在block中可以修改全局变量,因为全局变量在任何作用域都可以调用,block不会对其进行捕获。

4、对象局部变量

1-4.png

block对对象局部变量是指针捕获,会对其强引用,在内部可以修改变量而不报错

二、__block的作用

1、__block可以用于解决block内部无法修改auto变量值的问题

2-1.png
从2-1中可以看到加了__block修饰后,在block内部修改age就不会报错了

2、__block不能修饰全局变量、静态变量(static)

2-2.png

3、编译器会将__block变量包装成一个对象

2-3.png

2-3加了__block

2-4.png

2-4没加__block
从2-3中可以看到,加了__block后,内部age是一个__Block_byref_age_0对象

三、__block原理

  • 编译器会将__block变量包装成一个对象,变成对象后就可以根据指针地址在block内部去修改外部的变量


    2-3.png
struct __Block_byref_age_0 {
  void *__isa;
__Block_byref_age_0 *__forwarding;
 int __flags;
 int __size;
 int age;
};

__Block_byref_age_0中包含了isa指针,所以变量为对象。
__forwarding是指向自己的指针
age是变量的值
block通过__forwarding指针去修改age的值

四、__block的内存管理

  • 当block在栈上时,并不会对__block变量产生强引用
  • 当block被copy到堆时,会调用block内部的copy函数,copy函数内部会调用_Block_object_assign函数,_Block_object_assign函数会对__block变量形成强引用(retain)
  • 当blcok从堆中移除时,会调用block内部的dispose函数,dispose函数内部会调用_Block_object_dispose函数,_Block_object_dispose函数会自动释放引用的__block变量(release)
        __block int age = 10;
        void (^block)(void) = ^{
            NSLog(@"%d",age);
        };
        age = 20;
        block();

这里个Block里输出的age为20,因为加了__block修饰符后,编译器会将__block变量包装成一个对象,block对其是指针捕获,可以通知指针去修改值。

  • __block去修饰对象时,在oc层面看不出有什么变化,编译成c++时,可以看到内存管理跟没有__block还是有区别的
struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_person_0 *person; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_person_0 *_person, int flags=0) : person(_person->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

不加__block时,block是直接强引用的Person对象,但是现在是对__Block_byref_person_0进行了强引用。

struct __Block_byref_person_0 {
  void *__isa;
__Block_byref_person_0 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 Person *person;
};

__Block_byref_person_0内部才是对Person对象强引用,比没有__block多了__Block_byref_person_0这一步。__Block_byref_person_0内部还有一个__Block_byref_id_object_copy和__Block_byref_id_object_dispose,其作用跟block内部的copy和dispose一样,可以滑到上面看block的copy和dispose的讲解。

Block变量捕获详解(一)
Block的三种类型(二)
Block对象变量捕获(三)
Block循环引用(五)

相关文章

  • block 基本使用

    一、函数指针的作用 二、block的定义与调用方式 三、typedef block 四、block 修饰符 五、b...

  • iOS面试之Block大全

    Block Block内容如下: 关于Block 截获变量 __block修饰符 Block的内存管理 Block...

  • iOS面试之Block模块

    Block Block内容如下: 关于Block 截获变量 __block修饰符 Block的内存管理 Block...

  • 2022-04-13 block笔记

    什么是block 什么是block调用 block截获变量 __block修饰符用在什么场景,__block变量_...

  • Block

    Block介绍 截获变量 __block修饰符 Block的内存管理 Block的循环引用 一、Block介绍 1...

  • IOS_Block_定义

    [TOC] Declare c语言中方法修饰符 ( ) ,如定义一个方法: block指针修饰符^block指针修...

  • block:__block修饰符和__block变量

    一、block执行体里无法修改外界的普通局部变量,可以用__block修饰符修饰一下二、__block修饰符的底层...

  • __block修饰符(四)

    一、不加__block修饰符的情况下在block内部修改变量 1、基本数据类型的auto局部变量 在block中无...

  • iOS 面试全方位剖析 -- Block篇

    block 介绍 截获变量 __block修饰符 Block的内存管理 Block的循环引用 为什么 weakSe...

  • iOS-Block知识点整理

    block 介绍 截获变量 __block修饰符 Block的内存管理 Block的循环引用 为什么 weakSe...

网友评论

      本文标题:__block修饰符(四)

      本文链接:https://www.haomeiwen.com/subject/vkuqwltx.html