写高质量OC代码52建议总结:37.理解“块”

块和函数类似,只是直接定义在另一个函数里,和定义它的函数共享同一个范围里的东西。用“^”来表示。
 ^{
    //block
 };
 块和int,float或其他对象一样,可以作为一个值赋给变量并使用。块类型的语法和函数指针类似。
 void (^someBlock)() = ^{
    //block
 };
 块类型的语法结构:
 return_type (^block_name)(parameters)
 接收两个int做参数,并返回int值:
 int (^addBlock)(int a,int b) = ^(int a, int b) {
    return a + b;
 };
 定义好后,可以使用:
 int add = addBlock(2, 5);
 block的好处是,在它的声明范围里,所有的变量都可以被捕获。那个范围里的变量,在块里依然可以使用
int additional = 5;
 int (^addBlock)(int a, int b) = ^(int a, int b){
    return a + b + additional;
 };
 int add = addBlock(2, 5);
 默认情况下,块所捕获的变量是不可以在块中修改的,如果改变additional的值,编译器就会报错。变量声明的时候可以加上__block修饰符,就能在块中修改变量了。
 NSArray *array = @[@0, @1, @2, @3, @4, @5];
 __block NSInteger count = 0;
 [array enumerateObjectUsingBlock:^(NSNumber *number, NSUInteger idx, BOOL *stop){
    if ([number compare:@2] == NSOrderedAscending) {
        count++;
    }
 }];
 传递给enumerateObjectUsingBlock的块事先并没有赋值给局部变量,而是直接内联在函数调用里。
 如果快所捕获的变量是对象类型,那么就会自动保留它。系统释放这个块的时候,也会将其一并释放。块本身也有引用计数。
 如果将块定义在OC类中的实例方法中,可以使用self变量。块总能修改实例变量,在声明的时候无需加上__block。如果通过读取或写入操作捕获了实例变量,也会把self获取了,因为实例变量是和self关联在一起的。
 
@interface EOCClass
 -(void)anInstanceMethod {
    void (^someBlock)() = ^{
        _anInstanceVariable = @"Something";
        NSLog(@"_anInstanceVariable = %@", _anInstanceVariable);
    };
 }
 @end
 如果某个EOCClass实例正在执行anInstanceMethod方法,self变量就指向此实例。由于块里没有明确使用self变量,所以很容易疏忽。直接访问实例变量和通过self访问是等效的:
 
self->_anInstanceVariable = @"Something";
self.anInstanceVariable = @"Something";
 self也是一个对象,块在捕获它的时候也会将其保留。如果self那个对象同时也保留了块,就会形成保留环。
 
 定义块的时候,其所占的内存区域是分配在栈中的。块只在定义它那个范围里有效。
 
void (^block)();
 if(/...../) {
    block = ^{
        NSLog(@"Block A");
    }
 } else {
    block = ^{
        NSLog(@"Block B");
    }
 }
 block();
 定义在if 和 else 的语句中两个block都分配在栈中。编译器会给每个块分配好栈内存,等离开相应范围后,分配给块的内存可能被覆写掉。两个块只能在对应的if else 语句范围内有效。这样写可以编译,运行时而有效时而错误。没覆写,程序正常运行,已覆写,程序崩溃。
 可以给块对象发送copy消息,把块从栈拷贝到堆。块就可以在定义它的范围外使用了。
 只需要给两个block加上copy方法,就可以变得安全。
 
void (^block)();
    if(/...../) {
        [block = ^{
            NSLog(@"Block A");
        } copy];
    } else {
        [block = ^{
            NSLog(@"Block B");
        } copy];
    }
 block();
全局块,这种块不会不捉任何状态,块所使用的整个内存区域,在编译器已经完全确定了。全局块可以声明在全局内存里,全局块的拷贝是个空操作,因为全局块不可能被系统回收,这种块相当于单例。
 void (^block)() = ^{
    NSLog(@"This is a block");
 };
 
 总结:
 1.块是C、C++、OC中的词法闭包。
 2.块可以接收参数,也可以返回值。
 3.块可以分配在栈或者堆上,也可以是全局的。分配在栈上的块可以拷贝到堆里,这样就和对象一样具备引用计数了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值