一,基础认识
block的声明
很像函数指针,把 * 换成^ 。前面是返回类型,中间是块名,最后是参数类型。
// returnType (^BlockName) (Parameters)
int (^YourBlockName) (int, int);
// 简化声明, typedef登场
typedef int(^FuncAdd)(int, int);
FuncAdd add = ^int(int a, int b) {
return a+b;
};
add(100, 200);
block的实现
// ^returnType(Parameters){/*Put your code abcdefg */};
^int(int a, int b) {
return a+b;
};
返回值类型是可省略, 可自动判断,如果参数也是空,可简化成这样式儿的:
^( ) {
;
};
你可能会觉得,“这是啥啊!”。。
block的使用
根调用C函数一个样
YourBlockName(100, 200)
block特性
捕获 声明所在范围的所有变量。
int count = 0;
count = 1;
int (^block2)(void) = ^{
return count;
};
count = 2;
int value = block2(); // value = 1
却不能在block中修改捕获到的这些变量,尝试修改编译器报错。
[图片上传失败...(image-b9b6c3-1574265520804)]
)
__block 修饰de变量可在块中修改 值
__block int count = 0;
int (^MyBlock)(void) = ^{
count = 5;
return count ;
};
int value1 = count; // 0
int value2 = MyBlock(); // 5
int value3 = count; // 5
捕获变量只是拷贝了一份变量的值,用 __block 修饰后拷贝的是变量的地址.
循环引用de问题
例如ClassA持有block,block 中又用到了self. 循环引用 内存泄漏了。。。
__weak typeof(self) weakSelf = self;
YourBlock = ^{
__strong typeof(self) strongSelf = weakSelf;
NSLog(@"%@", strongSelf.********);
};
二,深入理解
block 的本质是啥呢?
/* Revised new layout. */
struct Block_descriptor {
unsigned long int reserved;
unsigned long int size;
void (*copy)(void *dst, void *src);
void (*dispose)(void *);
};
struct Block_layout {
void *isa; // 是个对象
int flags;
int reserved;
void (*invoke)(void *, ...); // 函数指针
struct Block_descriptor *descriptor;
/* Imported variables. */
};
类型
OC 中共有3种:
全局块,不访问任何外部变量
栈块,保存在栈中, 函数退出就被销毁,通过copy可复制到堆上。
堆块,保存在堆中。
MRC 的环境下运行下面的代码:
void (^globalBlock)() = ^{ NSLog(@"I am global block"); };
NSLog(@"%@", globalBlock);
NSString *string1 = @"I am stack block";
void (^stackBlcok)() = ^{ NSLog(@"%@", string1); };
NSLog(@"%@", stackBlcok);
NSString *string2 = @"I am malloc block";
void (^mallockBlock)() = [^{ NSLog(@"%@", string2); } copy];
NSLog(@"%@", mallockBlock);
<__NSGlobalBlock__: 0x1000053b0>
<__NSStackBlock__: 0x8fff5fbcc540>
<__NSMallocBlock__: 0x201503da0>
网友评论