一、Block本质
Block本质上是一个OC对象,内部也有个isa指针
二、Block的底层源码
- 1、测试代码
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//定义一个无参无返回值的block revanBlock
void(^revanBlock)(void) = ^{
NSLog(@"定义一个block");
};
//调用block
revanBlock();
}
@end
打印输出:
定义一个block
- 2、进入ViewController.m文件的目录下载命令行中执行一下命令转成C++代码
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc ViewController.m -o ViewController.cpp
- 3、ViewController.cpp¡ Block底层源码.png
- 4、经过简化后的代码
- 4.1、定义revanBlock
//定义revanBlock
void(*revanBlock)(void) =
&__ViewController__viewDidLoad_block_impl_0(
__ViewController__viewDidLoad_block_func_0,
&__ViewController__viewDidLoad_block_desc_0_DATA
);
- 4.2、调用block
//调用revanBlock
(revanBlock->FuncPtr)(revanBlock);
- 4.3、__ViewController__viewDidLoad_block_impl_0结构体
/**
1、__ViewController__viewDidLoad_block_impl_0:是一个结构体
2、C++中的结构体是可以存放函数
3、第一个元素:impl是一个struct __block_impl类型的结构体
struct __block_impl {
void *isa;//OC本质isa执行class对象
int Flags;
int Reserved;//保留字段
void *FuncPtr;//block代码地址
};
4、第二个元素:Desc是一个struct __ViewController__viewDidLoad_block_desc_0类型结构体指针
static struct __ViewController__viewDidLoad_block_desc_0 {
size_t reserved;//保留字段
size_t Block_size;//revanBlock的占用内存大小
}
5、C++中的构造函数(类似OC初始化方法)
5.1、第一个参数fp指针
5.2、第二个参数desc指针
5.3、第三个参数flags默认值为0
5.4、给结构体赋值
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
*/
struct __ViewController__viewDidLoad_block_impl_0 {
struct __block_impl impl;
struct __ViewController__viewDidLoad_block_desc_0* Desc;
//C++中的构造函数(类似OC初始化方法)
__ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
- 4.4、定义revanBlock时传入的第一个参数__ViewController__viewDidLoad_block_func_0是一个函数,所以从上面的分析可以知道,在定义block的时候把__ViewController__viewDidLoad_block_func_0这个函数当成参数fp指针传给了impl中的FuncPtr
static void __ViewController__viewDidLoad_block_func_0(struct __ViewController__viewDidLoad_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_ym_kg_kmbfn17v86dqrzyv26ww80000gn_T_ViewController_54ed6a_mi_0);
}
- 4.5、定义revanBlock时传入的第二个参数__ViewController__viewDidLoad_block_desc_0_DATA是一个函数
static struct __ViewController__viewDidLoad_block_desc_0 {
size_t reserved;
size_t Block_size;
} __ViewController__viewDidLoad_block_desc_0_DATA = { 0, sizeof(struct __ViewController__viewDidLoad_block_impl_0)};
- 5、调用revanBlock
//调用revanBlock
(revanBlock->FuncPtr)(revanBlock);
- 由定义revanBlock可知,revanBlock对象存储这__ViewController__viewDidLoad_block_impl_0的地址,又由于__ViewController__viewDidLoad_block_impl_0结构体中第一位元素是struct __block_impl类型的结构体impl,并且通过构造函数把传进来的fp指针赋值给了impl元素中的元素FuncPtr。
- 小结:block是封装了函数调用以及函数调用环境的OC对象 block底层结构.png
三、Block变量捕获
1、局部变量
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
void(^revanBlock)(void);
- (void)viewDidLoad {
[super viewDidLoad];
// 1、定义一个局部变量
int var = 10;
// 2、定义一个无参无返回值的block revanBlock
revanBlock = ^{
NSLog(@"block中使用var=%d", var);
};
// 3、重新给var赋值
var = 22;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 调用block
revanBlock();
}
@end
打印输出
2018-07-06 00:46:45.153676+0800 01-Block本质[7329:464430] block中使用var=10
- 为什么输出的age不是22?
- 1、此时revanBlock的底层源码
struct __ViewController__viewDidLoad_block_impl_0 {
struct __block_impl impl;
struct __ViewController__viewDidLoad_block_desc_0* Desc;
//多了一个var变量
int var;
//C++构造函数多了一个_var参数
__ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, int _var, int flags=0) : var(_var) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
- 发现在这里捕获了block中使用的外界局部变量
2、使用static修饰的局部变量
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
void(^revanBlock)(void);
- (void)viewDidLoad {
[super viewDidLoad];
// 1、定义一个局部变量
static int var = 10;
// 2、定义一个无参无返回值的block revanBlock
revanBlock = ^{
NSLog(@"block中使用var=%d", var);
};
// 3、重新给var赋值
var = 20;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 调用block
revanBlock();
}
@end
打印输出:
2018-07-06 01:00:10.983673+0800 01-Block本质[7514:473562] block中使用var=20
- 这次问什么输出的是20?
struct __ViewController__viewDidLoad_block_impl_0 {
struct __block_impl impl;
struct __ViewController__viewDidLoad_block_desc_0* Desc;
//var现在是一个int类型的指针
int *var;
__ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, int *_var, int flags=0) : var(_var) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
- 即使是使用static修饰的局部变量依然会被block捕获
3、全局变量
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
void(^revanBlock)(void);
// 1、定义一个全局变量
int var = 10;
- (void)viewDidLoad {
[super viewDidLoad];
// 2、定义一个无参无返回值的block revanBlock
revanBlock = ^{
NSLog(@"block中使用var=%d", var);
};
// 3、重新给var赋值
var = 20;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 调用block
revanBlock();
}
@end
打印输出:
2018-07-06 01:05:36.830416+0800 01-Block本质[7579:478837] block中使用var=20
- block没有捕获全局变量
struct __ViewController__viewDidLoad_block_impl_0 {
struct __block_impl impl;
struct __ViewController__viewDidLoad_block_desc_0* Desc;
__ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
- 小结
- 如果block中使用局部变量,局部变量一定会被block捕获
- 如果block中使用全局变量,不会被block捕获 block的变量捕获.png
四、MRC下的Block的类型
1、block中不使用任何变量,Block为NSGlobalBlock类型
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
void(^revanBlock)(void);
- (void)viewDidLoad {
[super viewDidLoad];
revanBlock = ^{
NSLog(@"block中输出");
};
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 调用block
revanBlock();
NSLog(@"%@", [revanBlock class]);
[revanBlock release];
}
@end
打印输出:
2018-07-06 01:19:07.472305+0800 01-Block本质[7791:489628] block中输出
2018-07-06 01:19:07.472491+0800 01-Block本质[7791:489628] __NSGlobalBlock__
2、block中使用局部变量,block是NSStackBlock类型
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
void(^revanBlock)(void);
- (void)viewDidLoad {
[super viewDidLoad];
// 1、定义一个局部变量
int var = 10;
// 2、定义一个无参无返回值的block revanBlock
revanBlock = ^{
NSLog(@"block中使用var=%d", var);
};
// 3、重新给var赋值
var = 20;
revanBlock();
NSLog(@"%@", [revanBlock class]);
[revanBlock release];
}
@end
打印输出:
2018-07-06 01:29:34.738826+0800 01-Block本质[7960:498531] block中使用var=10
2018-07-06 01:29:34.739160+0800 01-Block本质[7960:498531] __NSStackBlock__
3、block中使用static修饰的局部变量,block是NSGlobalBlock类型
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
void(^revanBlock)(void);
- (void)viewDidLoad {
[super viewDidLoad];
// 1、定义一个局部变量
static int var = 10;
// 2、定义一个无参无返回值的block revanBlock
revanBlock = ^{
NSLog(@"block中使用var=%d", var);
};
// 3、重新给var赋值
var = 20;
revanBlock();
NSLog(@"%@", [revanBlock class]);
[revanBlock release];
}
@end
打印输出:
2018-07-06 01:31:44.566522+0800 01-Block本质[7989:500158] block中使用var=20
2018-07-06 01:31:44.566791+0800 01-Block本质[7989:500158] __NSGlobalBlock__
4、block中使用全局变量,block是NSGlobalBlock类型
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
void(^revanBlock)(void);
// 1、定义一个全局变量
static int var = 10;
- (void)viewDidLoad {
[super viewDidLoad];
// 2、定义一个无参无返回值的block revanBlock
revanBlock = ^{
NSLog(@"block中使用var=%d", var);
};
// 3、重新给var赋值
var = 20;
revanBlock();
NSLog(@"%@", [revanBlock class]);
[revanBlock release];
}
@end
打印输出:
2018-07-06 01:34:44.150311+0800 01-Block本质[8041:502465] block中使用var=20
2018-07-06 01:34:44.150554+0800 01-Block本质[8041:502465] __NSGlobalBlock__
五、在ARC下的Block的类型
1、block中不使用任何变量,block是NSGlobalBlock类型
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
void(^revanBlock)(void);
- (void)viewDidLoad {
[super viewDidLoad];
revanBlock = ^{
NSLog(@"block中输出");
};
// 调用block
revanBlock();
NSLog(@"%@", [revanBlock class]);
}
@end
打印输出:
2018-07-06 01:39:14.251938+0800 01-Block本质[8119:505911] block中输出
2018-07-06 01:39:14.252169+0800 01-Block本质[8119:505911] __NSGlobalBlock__
2、block中使用局部变量,block是NSMallocBlock类型
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
void(^revanBlock)(void);
- (void)viewDidLoad {
[super viewDidLoad];
// 1、定义一个局部变量
int var = 10;
// 2、定义一个无参无返回值的block revanBlock
revanBlock = ^{
NSLog(@"block中使用var=%d", var);
};
// 3、重新给var赋值
var = 20;
revanBlock();
NSLog(@"%@", [revanBlock class]);
}
@end
打印输出:
2018-07-06 01:40:46.853263+0800 01-Block本质[8147:507357] block中使用var=10
2018-07-06 01:40:46.853484+0800 01-Block本质[8147:507357] __NSMallocBlock__
3、block中使用static修饰的局部变量,block是NSGlobalBlock类型
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
void(^revanBlock)(void);
- (void)viewDidLoad {
[super viewDidLoad];
// 1、定义一个局部变量
static int var = 10;
// 2、定义一个无参无返回值的block revanBlock
revanBlock = ^{
NSLog(@"block中使用var=%d", var);
};
// 3、重新给var赋值
var = 20;
revanBlock();
NSLog(@"%@", [revanBlock class]);
}
@end
打印输出:
2018-07-06 01:42:20.169110+0800 01-Block本质[8171:508554] block中使用var=20
2018-07-06 01:42:20.169337+0800 01-Block本质[8171:508554] __NSGlobalBlock__
4、block中使用全局变量,block是NSGlobalBlock类型
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
void(^revanBlock)(void);
// 1、定义一个全局变量
int var = 10;
- (void)viewDidLoad {
[super viewDidLoad];
// 2、定义一个无参无返回值的block revanBlock
revanBlock = ^{
NSLog(@"block中使用var=%d", var);
};
// 3、重新给var赋值
var = 20;
revanBlock();
NSLog(@"%@", [revanBlock class]);
}
@end
打印输出:
2018-07-06 01:44:10.719455+0800 01-Block本质[8194:509956] block中使用var=20
2018-07-06 01:44:10.719677+0800 01-Block本质[8194:509956] __NSGlobalBlock__
- 小结
- block是基础NSBlock
- 当block中使用了局部变量(auto修饰)时,在MRC下block是NSStackBlock类型,在ARC下是NSMallockBlock类型
- 在其他情况下都是NSGlobalBlock类型
- 在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上
- block作为函数返回值时
- 将block赋值给__strong指针时
- block作为Cocoa API中的方法名含有usingBlock的方法参数时
-
block作为GCD API的方法参数时
block类型.png block不同的类型内存分配.png 不同类型的block执行copy操作.png
六、Block访问对象类型
1、block中访问局部对象类型
- 1、RevanPerson
#import <Foundation/Foundation.h>
@interface RevanPerson : NSObject
@property (nonatomic, assign) int age;
@end
#import "RevanPerson.h"
@implementation RevanPerson
@end
- 2、测试代码
#import "ViewController.h"
#import "RevanPerson.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 1、定义一个RevanPerson对象
RevanPerson *revan_p = [[RevanPerson alloc] init];
revan_p.age = 20;
// 2、定义一个无参无返回值的block revanBlock
void (^revanBlock)(void) = ^{
NSLog(@"block中使用对象%@ 年龄为%d", revan_p, revan_p.age);
};
// 3、调用block
revanBlock();
}
@end
打印输出:
2018-07-07 17:42:43.844470+0800 01-Block本质[5511:325252] block中使用对象<RevanPerson: 0x6000000135a0> 年龄为20
- 从底层的数据结构窥探一下在block中使用对象和在block中使用基本数据类型变量有什么区别
-1、定义block
//定义block
void (*revanBlock)(void) = ((void (*)())&__ViewController__viewDidLoad_block_impl_0((void *)__ViewController__viewDidLoad_block_func_0, &__ViewController__viewDidLoad_block_desc_0_DATA, revan_p, 570425344));
- 2、__ViewController__viewDidLoad_block_impl_0结构体,依然会会把用到的局部对象变量捕获到结构体中
struct __ViewController__viewDidLoad_block_impl_0 {
struct __block_impl impl;
struct __ViewController__viewDidLoad_block_desc_0* Desc;
RevanPerson *__strong revan_p;
__ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, RevanPerson *__strong _revan_p, int flags=0) : revan_p(_revan_p) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
- 3、struct __ViewController__viewDidLoad_block_desc_0结构体,与基本数据类型相比,多了copy函数和dispose函数
static struct __ViewController__viewDidLoad_block_desc_0 {
size_t reserved;
size_t Block_size;
//多了一个copy函数
void (*copy)(struct __ViewController__viewDidLoad_block_impl_0*, struct __ViewController__viewDidLoad_block_impl_0*);
//多了一个dispose函数
void (*dispose)(struct __ViewController__viewDidLoad_block_impl_0*);
}
- 4、__ViewController__viewDidLoad_block_desc_0_DATA函数
static struct __ViewController__viewDidLoad_block_desc_0 {
size_t reserved;
size_t Block_size;
//多了一个copy函数指针
void (*copy)(struct __ViewController__viewDidLoad_block_impl_0*, struct __ViewController__viewDidLoad_block_impl_0*);
//多了一个dispose函数指针
void (*dispose)(struct __ViewController__viewDidLoad_block_impl_0*);
} __ViewController__viewDidLoad_block_desc_0_DATA = {
0,
sizeof(struct __ViewController__viewDidLoad_block_impl_0),
__ViewController__viewDidLoad_block_copy_0,
__ViewController__viewDidLoad_block_dispose_0
};
把__ViewController__viewDidLoad_block_copy_0函数的地址赋值给copy
把__ViewController__viewDidLoad_block_dispose_0函数的地址赋值给dispose
- 4.1、__ViewController__viewDidLoad_block_copy_0函数中调用_Block_object_assign函数
static void __ViewController__viewDidLoad_block_copy_0(struct __ViewController__viewDidLoad_block_impl_0*dst, struct __ViewController__viewDidLoad_block_impl_0*src) {
//copy函数指针会调用_Block_object_assign函数
_Block_object_assign((void*)&dst->revan_p, (void*)src->revan_p, 3/*BLOCK_FIELD_IS_OBJECT*/);
}
- 4.2、__ViewController__viewDidLoad_block_dispose_0函数调用_Block_object_dispose函数
static void __ViewController__viewDidLoad_block_dispose_0(struct __ViewController__viewDidLoad_block_impl_0*src) {
//dispose函数指针会调用_Block_object_dispose
_Block_object_dispose((void*)src->revan_p, 3/*BLOCK_FIELD_IS_OBJECT*/);
}
- 小结:在block中访问对象类型变量和访问基本数据类型变量的区别
- 相同点:block中都会捕获变量
- 不同点:block中使用对象时,会多2个函数指针(copy,dispose)
2、没有强指针指向的Block对象中引用对象变量
- 1、RevanPerson
#import <Foundation/Foundation.h>
@interface RevanPerson : NSObject
@end
#import "RevanPerson.h"
@implementation RevanPerson
- (void)dealloc {
NSLog(@"RevanPerson -dealloc");
}
@end
- 2、测试代码
#import "ViewController.h"
#import "RevanPerson.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
{
// 定义一个RevanPerson对象
RevanPerson *revan_p = [[RevanPerson alloc] init];
//使用block
^{
NSLog(@"没有强指针的block对象中使用revan_p对象:%@", revan_p);
}();
NSLog(@"%@", [^{
NSLog(@"没有强指针的block对象中使用revan_p对象:%@", revan_p);
} class]);
}
NSLog(@"--- RevanPerson对象作用域之外 ---");
}
@end
打印输出:2018-07-07 19:32:37.465583+0800 01-Block本质[7527:406694] 没有强指针指向的block对象中使用revan_p对象:<RevanPerson: 0x60000000a630>
2018-07-07 19:32:37.465839+0800 01-Block本质[7527:406694] __NSStackBlock__
2018-07-07 19:32:37.465989+0800 01-Block本质[7527:406694] RevanPerson -dealloc
2018-07-07 19:32:37.466193+0800 01-Block本质[7527:406694] --- RevanPerson对象作用域之外 ---
- 小结:没有强指针指向的Block对象,并且在block中使用局部对象变量时,可以知道这个Block是一个NSStackBlock类型的,存储在栈区。所以当代码执行过作用域之外首先Block的栈内存会被系统回收,同时revan_p对象也没有强指针引用,所以revan_p对象也会被释放。
- 源码可知revan_p对象依然会被这个NSStackBlock类型的block捕获
struct __ViewController__viewDidLoad_block_impl_0 {
struct __block_impl impl;
struct __ViewController__viewDidLoad_block_desc_0* Desc;
RevanPerson *__strong revan_p;
__ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, RevanPerson *__strong _revan_p, int flags=0) : revan_p(_revan_p) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
3、有强指针指向的Block对象中引用对象变量
- 1、RevanPerson
#import <Foundation/Foundation.h>
@interface RevanPerson : NSObject
@end
#import "RevanPerson.h"
@implementation RevanPerson
- (void)dealloc {
NSLog(@"RevanPerson -dealloc");
}
@end
- 测试代码
#import "ViewController.h"
#import "RevanPerson.h"
typedef void(^RevanBlock)(void);
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
RevanBlock revan_block;
{
// 定义一个RevanPerson对象
RevanPerson *revan_p = [[RevanPerson alloc] init];
//使用block
revan_block = ^{
NSLog(@"有强指针指向的block对象中使用revan_p对象:%@", revan_p);
};
NSLog(@"%@", [revan_block class]);
}
NSLog(@"--- RevanPerson对象作用域之外 ---");
revan_block();
}
@end
打印输出:
2018-07-07 19:46:07.460595+0800 01-Block本质[7749:417687] __NSMallocBlock__
2018-07-07 19:46:07.460891+0800 01-Block本质[7749:417687] --- RevanPerson对象作用域之外 ---
2018-07-07 19:46:07.461208+0800 01-Block本质[7749:417687] 有强指针指向的block对象中使用revan_p对象:<RevanPerson: 0x60400001ab30>
2018-07-07 19:46:07.461326+0800 01-Block本质[7749:417687] RevanPerson -dealloc
- 小结:revan_block是NSMallocBlock类型的Block,存储在堆中。从这次的打印输出可以看出RevanPerson在出作用并没有立即释放,而是等到 revan_block()调用之后, revan_block销毁了之后,RevanPerson对象随后销毁。
- 源码分析
struct __ViewController__viewDidLoad_block_impl_0 {
struct __block_impl impl;
struct __ViewController__viewDidLoad_block_desc_0* Desc;
RevanPerson *__strong revan_p;
__ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, RevanPerson *__strong _revan_p, int flags=0) : revan_p(_revan_p) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
4、有强指针指向的Block对象中引用使用__week修饰的对象变量
- 1、RevanPerson
#import <Foundation/Foundation.h>
@interface RevanPerson : NSObject
@end
#import "RevanPerson.h"
@implementation RevanPerson
- (void)dealloc {
NSLog(@"RevanPerson -dealloc");
}
@end
- 2、测试代码
#import "ViewController.h"
#import "RevanPerson.h"
typedef void(^RevanBlock)(void);
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
RevanBlock revan_block;
{
// 定义一个RevanPerson对象
RevanPerson *revan_p = [[RevanPerson alloc] init];
__weak RevanPerson *weakRevan_p = revan_p;
//使用block
revan_block = ^{
NSLog(@"有强指针指向的block对象中使用weakRevan_p对象:%@", weakRevan_p);
};
NSLog(@"%@", [revan_block class]);
}
NSLog(@"--- RevanPerson对象作用域之外 ---");
revan_block();
}
@end
打印输出:
2018-07-07 19:52:19.223148+0800 01-Block本质[7853:421860] __NSMallocBlock__
2018-07-07 19:52:19.223364+0800 01-Block本质[7853:421860] RevanPerson -dealloc
2018-07-07 19:52:19.223496+0800 01-Block本质[7853:421860] --- RevanPerson对象作用域之外 ---
2018-07-07 19:52:19.223626+0800 01-Block本质[7853:421860] 有强指针指向的block对象中使用weakRevan_p对象:(null)
- 小结:revan_block这个Block依然是NSMallocBlock类型的Block,但是发现使用__weak修饰的对象weakRevan_p在作用域一过就立即释放。
- 源码分析
struct __ViewController__viewDidLoad_block_impl_0 {
struct __block_impl impl;
struct __ViewController__viewDidLoad_block_desc_0* Desc;
RevanPerson *__weak weakRevan_p;
__ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, RevanPerson *__weak _weakRevan_p, int flags=0) : weakRevan_p(_weakRevan_p) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
5、小结
- 当block的存储在栈上
- block不会对内部使用的对象变量产生强引用
- 当block的内存在堆上
- block在堆区时,在block内部使用对象变量时,会调用block内部的copy函数,copy函数会调用_Block_object_assign函数,_Block_object_assign函数会根据捕获的对象的修饰符类型做出相应的操作,最终决定block是对对象强引用还是若引用
- block销毁时,会调用block内部的dispose函数,根据dispose函数内部的_Block_object_dispose函数会自动释放引用的对象变量
网友评论