-
Notifications
You must be signed in to change notification settings - Fork 1
Block
Kevin775263419 edited this page Mar 12, 2019
·
1 revision
-
block本质上也是一个OC对象,它内部也有个isa指针
-
block是封装了函数调用以及函数调用环境的OC对象
-
block的底层结构如右图所示,基本上都是结构体,这只是一个大概的结构
isa flag reversed invoke descriptio
-
为了保证block内部能够正常访问外部的变量,block有个变量捕获机制
变量类型 捕获到block内部 访问方式 auto(局部) YES 值传递 static(局部) YES 指针传递 全局变量 NO 直接访问
- _NSGlobalBlock: 全局block
- _NSStackBlock: 栈block
- __NSMallocBlock: 堆block
block类型 | 环境 | 配置存储区域 | copy效果 |
---|---|---|---|
_NSGlobalBlock | 没有访问Auto变量 | 程序的数据区域 | 什么也不做 |
_NSStackBlock | 访问了Auto变量 | 栈区 | 从stack复制到heap |
__NSMallocBlock | __NSStackBlock__调用了copy | 堆区 | 引用计数增加 |
- block类型:block的类型
- 环境:是否capture的变量
- 配置存储区域:放在内存你的位置
- copy:执行copy的效果
- tips:NSStackBlock__调用了copy之后,就会变成MallocBlock,通过一个forwarding 指向栈区的block
- forwarding存在的作用,不论在内存的任何位置可以访问同一个block
-
在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如以下情况
- block作为函数返回值时
- 将block赋值给__strong指针时
- block作为Cocoa API中方法名含有usingBlock的方法参数时
- block作为GCD API的方法参数时
-
MRC下block属性的建议写法
@property (copy, nonatomic) void (^block)(void);
-
ARC下block属性的建议写法
@property (strong, nonatomic) void (^block)(void); @property (copy, nonatomic) void (^block)(void);
- 当block内部访问了对象类型的auto变量时
- 如果block是在栈上,将不会对auto变量产生强引用
- 如果block被拷贝到堆上
- 会调用block内部的copy函数
- copy函数内部会调用_Block_object_assign函数
- _Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用
- 如果block从堆上移除
- 会调用block内部的dispose函数
- dispose函数内部会调用_Block_object_dispose函数
- _Block_object_dispose函数会自动释放引用的auto变量(release)
-
__block可以用于解决block内部无法修改auto变量值的问题
-
__block不能修饰全局变量、静态变量(static)
-
编译器会将__block变量包装成一个对象
__block int age = 10; ^{ NSLog(@"age - %d",age); }();
- 当block在栈上时,并不会对__block变量产生强引用
- 当block被copy到堆时
- 会调用block内部的copy函数
- copy函数内部会调用_Block_object_assign函数
- _Block_object_assign函数会对__block变量形成强引用(retain)
- 当block从堆中移除时
- 会调用block内部的dispose函数
- dispose函数内部会调用_Block_object_dispose函数
- _Block_object_dispose函数会自动释放引用的__block变量(release)
- 如果是stackBlock,forwarding指针指向自己。
- 当stackBlock复制到heapBlock中时,原来stack中的forwarding指针指向,heapBlock中的结构体
正常情况下一般会有这3种方案解决
typedef void (^Block)(void);
@property (nonatomic, copy) Block block;
//解决方案
//__weak
__weak typeof (self) weakSelf = self;
self.block = ^{
printf("%p",weakSelf);
};
//__unsafe_unretained
__unsafe_unretained id unretainSelf = self;
self.block = ^{
printf("%p",unretainSelf);
};
//__block(need invocation block)
__block id blockSelf = self;
self.block = ^{
printf("%p",blockSelf);
blockSelf = nil;
};
self.block();
- 用__weak 修饰
- 用__unsafe_unretained修饰
- 用__block修饰(注意:需要调用block,同时blockSelf需要滞空)
建议使用YYKit库里面的封装
将下面这段代码复制到pch文件中,调用方法如下面的例子。比较简单好用
/**
Synthsize a weak or strong reference.
Example:
@weakify(self)
[self doSomething^{
@strongify(self)
if (!self) return;
...
}];
*/
#ifndef weakify
#if DEBUG
#if __has_feature(objc_arc)
#define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
#else
#define weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
#endif
#else
#if __has_feature(objc_arc)
#define weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
#else
#define weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
#endif
#endif
#endif
#ifndef strongify
#if DEBUG
#if __has_feature(objc_arc)
#define strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
#else
#define strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
#endif
#else
#if __has_feature(objc_arc)
#define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
#else
#define strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
#endif
#endif
#endif