@universal
2019-01-24T07:24:53.000000Z
字数 2429
阅读 271
iOS
block是在iOS 4.0之后才出现的,它可以将一段代码封装起来作为变量使用。
block声明:
返回值 (^block名称) (参数列表...)
如: void (^blockName)(int arg1, int arg2)
block定义(实现):
blockname = ^(int arg1, int arg2){
//do something
}
如下:
int (^addTwoNumber)(int a, int b) = ^(int a, int b) {return a + b;};
block的作用类似java中接口回调,但仅仅是作用类似,原理上完全是两个东西。
举例:作为参数回调使用:
//block无参数dispatch_async(dispatch_get_main_queue(), ^{NSLog(@"ui refresh");});//block带参数AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];[manager GET:@"url" parameters:parameters progress:^(NSProgress *_Nonnull downloadProgress) {NSLog(@"downloadProgress-->%@", downloadProgress);} success:^(NSURLSessionDataTask *_Nonnull task, id _Nullable responseObject) {NSLog(@"success %@", responseObject);}} failure:^(NSURLSessionDataTask *_Nullable task, NSError *_Nonnull error) {NSLog(@"error %@", error);}];
block还能实现链式调用,返回一个block对象,并在block中返回自身对象。
int main(int argc, const char * argv[]){@autoreleasepool {Person *p = [[Person alloc] init];p.study(@"xx宝典").run().study(@"xx技能");}return 0;}//Person.h@interface Person : NSObject- (Person *(^)(NSString *name))study;- (Person *(^)())run;@end//Person.m@implementation Person- (Person *(^)(NSString *))study{return ^(NSString *name){NSLog(@"study----%@", name);return self;};}- (Person *(^)())run{return ^{NSLog(@"run----");return self;};}@end
注意:
1、block的内存中有一块是专门来捕获变量的,在声明的block的范围内,所有变量都可以被其捕获。但是对外部变量只能读,如果想要修改,需要给变量加上__block关键字修饰。
2、避免循环引用, 使用__weak关键字来修饰需要引用的外部对象,防止导致内存泄漏。
3、可以利用typedef对block进行别称定义,减少代码量,增加可读性,将“对象抽象成类”。比如:typedef void(^SayHello)();
1、block是一个函数对象,是在运行时产生的,在一个作用域中生成的block对象分配在栈上,离开作用域,就不存在了(可以利用copy将block对象拷贝到堆上)。
每个对象都会有一个isa指针,那么根据isa指针类型,block有三种:
全局静态(globalBlock)/保存在程序的数据区域中(.data区)
出作用域销毁(stackBlock)/保存在栈中,
retainCount=0销毁(mallocBlock)/保存在堆中
2、block访问普通外部变量时,会将变量的值以“const方式”copy一份到block所在内存空间,所以block内部访问的并不是真正的外部变量,而且因为是const方式,所以编译器不允许修改copy的变量。
typedef void (^CustomBlock)(void);// 外部变量int value = 0;NSLog(@"block外部访问:value = %d", value);NSLog(@"block外部访问:value的地址是:%p", &value);CustomBlock block = ^{NSLog(@"block内部访问:value = %d", value);NSLog(@"block内部访问:value的地址是:%p", &value);};block();NSLog(@"block回到外部访问:value的地址是:%p", &value);
输出:
block外部访问:value = 0
block外部访问:value的地址是:0x7ffeea11a0c4
block内部访问:value = 0
block内部访问:value的地址是:0x600003cc10a0
block回到外部访问:value的地址是:0x7ffeea11a0c4
还有,要注意一点:若将变量定义为__block形式,那么变量的地址将会在block结束后改为block中copy生成的新地址。
3、其实由上可以看出,在block中引用对象,会导致对象的生命周期被延长,特别是当某些大文件被block访问时,有几率会导致内存访问不足。
4、利用block做回调时,在避免循环引用的同时,还要防止引用的对象被提前释放,从而可能会因为操作nil对象导致crash,或者执行一些无意义的逻辑。所以需要我们在block内部操作时加上保护代码。(这种场景在网络访问的情景下较为常见)。
未完待续。。。