IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> iOS - Block简单解析 -> 正文阅读

[C++知识库]iOS - Block简单解析

blocks简介

Blocks是C语言的扩充功能:带有自动变量(局部变量)的匿名函数

匿名函数就是不带名称的函数,在C语言中不允许这种函数存在。在C语言中为了调用函数,必须使用该函数的名称,即使使用函数指针来直接调用函数,虽然似乎不用知道函数名也能够使用该函数,但是其实只是似乎,其实还是需要的,所以就是说在C语言中,不能使用匿名函数这种不带名称的函数

但是当我们有了Blocks,源代码中就能够使用匿名函数,即不带名称的函数

那么带有局部变量是什么意思呢。

书上举了两个例子,当使用C语言的时

  • 关于几种变量的特点

    c语言函数中可能使用的变量:

    函数的参数 自动变量(局部变量) 静态变量(静态局部变量) 静态全局变量 全局变量

    由于存储区域特殊,其中有三种变量可以在任何时候以任何状态调用:

    静态变量(静态局部变量) 静态全局变量 全局变量

使用全局变量来多次调用函数,该变量值总能保持不变所以可以进行调用。

但是多个按钮(可以看作参数)之间的传值的时候就会出现问题,这个时候全局变量也并不能很好的解决,可以使用函数参数传递

在使用C++和Object—C的时候使用类可以保持变量值并多次持有该变量自身,由类生成的实例或对象保持该成员变量的值

但是使用C++或object—C增加了代码长度,所以使用blocks最好啦,blocks又满足条件又简短

block语法

^void (int event) {
      printf("buttonId:%d event=%d\n", i, event);
  }

block语法和C语言函数定义相比

1.没有函数名 因为它是匿名函数

  1. 带有“^“ 因为iOS应用程序的源代码中将大量使用Block,所以插入该记号便于查找

Block语法的BN范式

^ 返回值类型 参数列表 表达式

Block语法中可以省略的类型

  1. 返回值类型:如果表达式中有return语句就使用该返回值的类型,如果没有就使用void类型。表达式中如果有多个return语句时,所有return的返回值类型必须相同。
  2. 参数列表:如果不使用参数,参数列表也可以省略,比如^void (void) {printf (“blocks”);} 在省略了参数列表以及返回值类型之后^{printf (“blocks”);}

书上说返回值类型和参数列表均被省略的block语法是大家最为熟知的记述吧?

Block类型变量

C语言中,可以将所定义函数的地址赋值给函数指针类型变量中

int (*funcptr)(int) = &func;

在block语法下,一旦使用block语法就相当于生成了可赋值给Block类型变量的“值”

block类型变量与一般的C语言变量完全相同,可作为以下用途使用

自动变量 函数参数 静态变量 静态全局变量 全局变量

声明Block类型变量的示例如下所示

int (^blk) (int);
  1. 将Block语法赋值给声明为Block类型的变量中
int (^blk) (int) = ^(int count){return count + 1;};

左侧是block声明,右侧是block定义

  • 等号左侧的代码表示了这个Block的类型:它接受一个int参数,返回一个int值。
  • 等号右侧的代码是这个Block语法:相当于生成了可赋值给Block类型变量的“值”,它是等号左侧定义的block类型的一种实现。

因为通常的变量相同,当然也也可以这样写

int (^blk1)(int) = blk;

int (^blk2)(int);
blk2 = blk1;
  1. 使用Block类型变量

在函数参数中使用Block类型变量可以向函数传递Block

void func(int (^blk)(int)) {

//typedef
void func(blk_t blk)

在函数返回值中指定Block类型,可以将Block作为函数返回值返回

int (^func()) (int)
{
    return ^(int count){return count + 1;};
}

//typedef
blk_t func(){

为了简化,我们可以使用typedef来解决问题

typedef int (^blk_t)(int);

通过使用typedef可声明

  1. 调用Block(函数调用和函数参数)

赋值给Block类型变量中的Block方法像C语言通常的函数调用那样使用,这种方法与使用函数指针类型变量调用函数的方法几乎完全相同

//调用指针类型变量
int result = (*funcptr)(10);
//调用Block类型变量
int result = blk(10);

在函数参数中使用Block类型变量并在函数中执行Block的例子如下:

int func(blk_t blk, int rate)
{
		return blk(rate);
}

//在OC中
-int) methodUsingBlock:(blk_t)blk rate:(int)rate
{
		return blk(rate);
}
  1. Block指针类型变量
blk_t *blkptr = &blk;

iOS中Block的用法,举例,解析与底层原理(这可能是最详细的Block解析) - CocoaChina_一站式开发者成长社区

可以参考这篇文章中Block的常见用法以及语法总结(声明及定义语法),写的非常的好

Block的本质

block本质也是一个OC对象,封装了函数调用和函数调用环境

//写一个简单的BLock
int main(int argc, const char * argv[]) {
    @autoreleasepool {


        void (^block)(void) = ^{
            NSLog(@"132314234");
        };

        block();
    }
    return 0;
}

//转化为C++
struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  //构造函数
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_p__1kwt86gs28xdwnz5cds254400000gn_T_main_bf9aba_mi_0);
        }

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
				//定义block变量,删掉强制转换的部分
				void (*block)(void) = &__main_block_impl_0(
																				__main_block_func_0,
																			  &__main_block_desc_0_DATA);
        //void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
				 //执行block内部的代码
				 block->FuncPtr(block);
        //((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);

    }
    return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

block指向__main_block_impl_0,看__main_block_impl_0返回什么,它返回一个结构体

__main_block_impl_0是一个结构体,在结构体里面有一个构造函数(不用返回值,C++中参数有默认值可以不传值),初始化,将参数赋给结构体中struct __block_impl implstruct __main_block_desc_0* Desc,最终返回一个结构体

__main_block_func_0是一个函数,在__main_block_impl_0中将这个函数的地址传给了fp参数,fp参数继续传给了__main_block_impl_0中的FuncPtr

struct __main_block_desc_0* Desc指向struct __main_block_desc_0这个结构体,这个结构体计算block的大小

最后通过funcPtr调用__main_block_func_0函数,将Block地址传进去执行Block代码

Block截获变量

先上图
请添加图片描述

对局部变量的截获

局部变量

它是自动对象(auto),只在函数执行期间存在,离开作用域就销毁 截获方式为值截获

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int a;
        void (^block)(void) = ^{
            NSLog(@"a = %d", a);
        };
        block();
    }
    return 0;
}

//C++
struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  //值截获
  int a;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

		int a;
        void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));

静态局部变量

只对定义自己的函数体始终可见,截获方式为指针截获

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        
        static int a;
        

        void (^block)(void) = ^{
            
            NSLog(@"a = %d", a);
        };

        block();
    }
    return 0;
}

//C++
struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  //指针截获
  int *a;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_a, int flags=0) : a(_a) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 


        static int a;


        void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, &a));

        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
    return 0;
}

对象类型:

Block对对象类型的auto变量的截获,重点是对象类型 在这里插入图片描述

  • 当对象的修饰符是__strong时
//当对象的修饰符是__strong时
typedef void (^MyBlock)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        MJPerson *person = [[MJPerson alloc] init];

        //__block __weak MJPerson *weakPerson = person;

        MyBlock block = ^{
            NSLog(@"%p", person);
        };

        block();
    }
    return 0;
}

C++
//copy函数的调用
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);}

//主要变化在这个函数,比之前auto变量的时候多了copy和dispose函数
static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};

//对比之前的静态局部变量
static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

MyBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_weakPerson_0 *)&weakPerson, 570425344));
  • 当对象的修饰符是__weak时
//当对象的修饰符是__weak时
int main(int argc, const char * argv[]) {
    @autoreleasepool {

        MJPerson *person = [[MJPerson alloc] init];

        __block __weak MJPerson *weakPerson = person;

        MyBlock block = ^{
            NSLog(@"%p", weakPerson);
        };

        block();
    }
    return 0;
}

//c++
//我们可以看到,对比上面的__strong修饰符,src->weakPerson, 变成了weak
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) 
{_Block_object_assign((void*)&dst->weakPerson, (void*)src->weakPerson, 8/*BLOCK_FIELD_IS_BYREF*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->weakPerson, 8/*BLOCK_FIELD_IS_BYREF*/);}

//从上面的strong复制过来的
//static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);}

//static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};

MyBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_weakPerson_0 *)&weakPerson, 570425344));
  • 用我自己通俗一点的话来说就是:
    我们在上面也可以看到,对比之前的auto变量和静态局部变量,多了两个copy和dispose函数
    如果Block访问的是对象类型,就会自动生成copy和dispose函数,来对对象进行内存原理
    如果Block访问的是自动变量auto,就没有这两个函数
    在对象类型中有__strong 和__weak 两种修饰符,给当地进行初始化和废弃,为此需要增加成员变量copy和dispose
    但是auto自动变量就用不到,所以它也没有copy和dispose这两个函数
    在这里插入图片描述

Block对__block变量的截获

在有__block修饰符的时候,当Blockcopy到堆上时,会把__block也copy到堆上,即Block对__block的截获。
请添加图片描述
请添加图片描述对于__block变量的截获,同样会调用copy和dispose函数。

typedef void (^MyBlock)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        MJPerson __block *person = [[MJPerson alloc] init];

        //__block  MJPerson *person = person;

        MyBlock block = ^{
            NSLog(@"%p", person);
        };

        block();
    }
    return 0;
}

typedef void (*MyBlock)(void);


//__block函数,编译器会将__block变量包装成一个对象
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*);
 MJPerson *__strong person;
};

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;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  __Block_byref_person_0 *person = __cself->person; // bound by ref

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_p__1kwt86gs28xdwnz5cds254400000gn_T_main_080995_mi_0, (person->__forwarding->person));
        }
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 8/*BLOCK_FIELD_IS_BYREF*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->person, 8/*BLOCK_FIELD_IS_BYREF*/);}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        __Block_byref_person_0 person = {(void*)0,(__Block_byref_person_0 *)&person, 33554432, sizeof(__Block_byref_person_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((MJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)((MJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("MJPerson"), sel_registerName("alloc")), sel_registerName("init"))};



        MyBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_person_0 *)&person, 570425344));

        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
    return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

另外我们要注意当block被copy到栈上时,对__block变量一直都是强引用

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        MJPerson  *person = [[MJPerson alloc] init];

        __block  MJPerson *weakperson = person;

        MyBlock block = ^{
            NSLog(@"%p", weakperson);
        };

        block();
    }
    return 0;
}


//对__block仍然是强引用
struct __Block_byref_weakperson_0 {
  void *__isa;
__Block_byref_weakperson_0 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 MJPerson *__strong weakperson;
};

对象类型的auto变量、__block变量的对比

他们都调用了copy和dispose函数,不过这两个函数在被它们调用的时候有细微的差别。
在这里插入图片描述

对全局变量的截获

全局变量,不截获,直接取值

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int age = 10;
        static int height = 10;
        void (^block)(void) = ^{
            NSLog(@"age = %d, height = %d", age, height);
        };
        age = 20;
        height = 20;
        block();
    }
    return 0;
}

//输出结果
age = 10, height = 20

C++
struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int age;
  int *height;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int *_height, int flags=0) : age(_age), height(_height) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  int age = __cself->age; // bound by copy
  int *height = __cself->height; // bound by copy

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_p__1kwt86gs28xdwnz5cds254400000gn_T_main_023eda_mi_0, age, (*height));
        }

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        int age = 10;
        static int height = 10;
        void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, 
																	age, &height));
																	//值截获和指针截获   跨函数返回值所以要捕获
        age = 20;
        height = 20;
        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
    return 0;
}

//全局变量
int age_ = 10;
static int height_ = 10;

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        void (^block)(void) = ^{
            NSLog(@"age = %d, height = %d", age_, height_);
        };
        age_ = 20;
        height_ = 20;
        block();
    }
    return 0;
}
//并没有 捕获到结构体里面
int age_ = 10;
int height_ = 10;

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

//直接调用
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_p__1kwt86gs28xdwnz5cds254400000gn_T_main_a9b1b8_mi_0, age_, height_);
        }
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);

Block的三种类型

Block存储域

  • _NSConcreteStackBlock类,存储域:栈
  • _NSConcreteGlobalBlock类,存储域:数据区
  • _NSConcreteMallocBlock类,存储域:堆

在这里插入图片描述

Block类型存在的环境

MRC:
在这里插入图片描述
1. _NSConcreteGlobalBlock类,存储域:数据区
没有截取的情况即没有访问auto变量(全局变量)?(静态局部变量)

静态局部变量

在这里插入图片描述

全局变量
在这里插入图片描述
2. _NSConcreteStackBlock类,存储域:栈
一般是访问了局部变量(auto),但是因为随时可能会回收所以很多时候都要Block
下图因为是在ARC情况下,它自动copy了,所以在堆上(Malloc)
在这里插入图片描述
3. _NSConcreteMallocBlock类,存储域:堆 栈上的copy到堆
如上图

ARC下一般直接就是Malloc或者Global,因为自动copy了

  1. 全局变量(即没有访问auto变量的)都是Global
  2. 局部变量(auto)一般自动进行copy后到堆上(Malloc)
  3. copy之后,Global还是Global,Stack变为Malloc。Malloc引用计数增加

复制(copy)效果

在这里插入图片描述

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

比如以下情况

  • block作为函数返回值时
  • 将block赋值给__strong指针时
  • block作为Cocoa API中方法名含有usingBlock的方法参数时
  • block作为GCD API的方法参数时
  1. block作为返回值时

在这里插入图片描述

  1. 将block赋值给__strong指针时

在这里插入图片描述

__Block说明符

修饰auto变量

__block修饰auto变量,解决Block内部不能修改auto变量的值的问题
编译器会将__block包装为一个对象

//__block说明符
typedef void (^MyBlock)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        __block int a = 10;
        MyBlock block = ^{
            a = 20;
            NSLog(@"--%d", a);
        };

        block();
    }
    return 0;
}

//C++
typedef void (*MyBlock)(void);

struct __Block_byref_a_0 { //__block对象结构体
  void *__isa;
__Block_byref_a_0 *__forwarding;
 int __flags;
 int __size;
 int a;//10
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_a_0 *a; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_a_0 *_a, int flags=0) : a(_a->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  __Block_byref_a_0 *a = __cself->a; // bound by ref
						 (a->__forwarding->a) = 20;//重点!__block修饰符赋值
            NSLog((NSString *)&__NSConstantStringImpl__var_folders_p__1kwt86gs28xdwnz5cds254400000gn_T_main_7a7b85_mi_0, (a->__forwarding->a));
        }
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        __attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 10};
       //简化版Block
				__Block_byref_a_0 a = {0,
 						&a, 
 						0, 
 						sizeof(__Block_byref_a_0),
 						1}; 
				MyBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));

        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
    return 0;
}

__main_block_impl_0中有__Block_byref_a_0 *a,__block对象Block内部通过指针指向age。在__main_block_func_0中通过指向自己的指针(a->__forwarding->a)修改age,最后修改成功

在此有个forwarding指针需要解释一下
__forwaring在复制之前也就是__block变量配置在栈上的时候 指向的是__Block_byref_val_0结构体 也就是指向自身 复制之后到了栈上之后就指向了堆上的__block变量
通过__forwaring可以保证无论是在Block外使用__block变量 还是__block变量在栈上堆上 都可以顺利访问同一个__block变量
在这里插入图片描述

被__block修饰的对象类型

请添加图片描述

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        MJPerson  *person = [[MJPerson alloc] init];

        __block  MJPerson *blockperson = person;

        MyBlock block = ^{
            NSLog(@"%p", blockperson);
        };

        block();
    }
    return 0;
}


typedef void (*MyBlock)(void);

struct __Block_byref_blockperson_0 {
  void *__isa;
__Block_byref_blockperson_0 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 MJPerson *__strong blockperson;
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_blockperson_0 *blockperson; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_blockperson_0 *_blockperson, int flags=0) : blockperson(_blockperson->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  __Block_byref_blockperson_0 *blockperson = __cself->blockperson; // bound by ref

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_p__1kwt86gs28xdwnz5cds254400000gn_T_main_499baa_mi_0, (blockperson->__forwarding->blockperson));
        }
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->blockperson, (void*)src->blockperson, 8/*BLOCK_FIELD_IS_BYREF*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->blockperson, 8/*BLOCK_FIELD_IS_BYREF*/);}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        MJPerson *person = ((MJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)((MJPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("MJPerson"), sel_registerName("alloc")), sel_registerName("init"));

        __attribute__((__blocks__(byref))) __Block_byref_blockperson_0 blockperson = {(void*)0,(__Block_byref_blockperson_0 *)&blockperson, 33554432, sizeof(__Block_byref_blockperson_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, person};

        MyBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_blockperson_0 *)&blockperson, 570425344));

        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
    return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

//mian中的简化

//__block NSObject *obj1 = obj;
__Block_byref_obj1_0 obj1 = {0,
                             &obj1,
                             33554432,
                             sizeof(__Block_byref_obj1_0),
                             __Block_byref_id_object_copy_131,
                             __Block_byref_id_object_dispose_131,
                             obj};


//blk1的初始化
Blk blk1 = &__main_block_impl_0(__main_block_func_0,
                                        &__main_block_desc_0_DATA,
                                        (__Block_byref_obj1_0 *)&obj1,
                                        570425344);

//blk1();
(blk1->FuncPtr)(blk1);

我觉得有个博主这一段解释的很好,引用过来
在这一过程中

  • Block截获__block变量,结构体中生成了指向__block变量的指针;
  • 而__block修饰的是一个对象类型的变量,即__block结构体中有一个对象类型的指针变量;
  • __block以及Block最初都在栈上,栈上的Block只是使用栈上的__Block变量,并不持有。 当Block复制到了堆上,截获的__block也会复制到堆上,通过Block的__main_block_copy_0、__main_block_dispose_0函数对__block进行相应的持有和释放。(上面这一段可以参考之前对局部变量的截获中对_block变量截获的内容)
  • 当__block复制到了堆上,那么就会使用__block中的__Block_byref_id_object_copy、__Block_byref_id_object_dispose并且根据对象类型的所有权修饰符(weak、strong)进行相应的强引用、弱引用、以及释放
  • 对象类型被__weak修饰,那么复制到堆上的__block会调用__Block_byref_id_object_copy持有对象的弱引用。对象类型被__strong修饰,那么复制到堆上的__block会调用__Block_byref_id_object_assign持有对象的强引用。
  • 堆上的__block被废弃时,若原来持有对象,使用__Block_byref_id_object_dispose释放所持有的对象。

避免循环引用

一个对象中强引用了block,在block中又使用了该对象,就会发生循环引用。
将该对象使用__weak或者__block修饰符修饰之后再在block中使用。
可以看这里Blocks实现里的循环引用

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-02 20:46:10  更:2021-08-02 20:46:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/10 2:18:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码