Block总结

block小结

定义:

1 Block是C语言的

2 Block是一个数据类型

3 是一个提前准备好的代码,在需要的时候执行

/**
 Block是C语言的
 Block是一个数据类型
 是一个提前准备好的代码,在需要的时候执行
 */
void demoBlock1();
void demoBlock2();
void demoBlock3();

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        demoBlock3();
    }
    return 0;
}


void demoBlock3() {
   
    // 指针记录的是地址
    NSMutableString *strM = [NSMutableString stringWithString:@"zhangsan"];
    NSLog(@"定义前 %p %p", strM, &strM);
   
    void (^myBlock)() = ^ {
        // 修改strM指针指向的内容
        [strM setString:@"lisi"];
        NSLog(@"inblock %p %p", strM, &strM);
       
        // 这句代码是修改strM指针指向的地址
//        strM = [NSMutableString stringWithString:@"wangwu"];
    };
    NSLog(@"定义后 %p %p", strM, &strM);
   
    myBlock();
    NSLog(@"%@", strM);
}


void demoBlock2() {
    // 使用 __block,说明不在关心x数值的具体变化
    __block int x = 10;
    NSLog(@"定义前 %p", &x);                 // 栈区
   
    // 如果要在block中,修改外部变量的数值,需要使用 __block 修饰符号
    // 定义block时,如果引用了外部使用__block的变量,block定义之后,外部变量的指针地址同样会变成堆区的地址
    void (^myBlock)() = ^ {
        x = 80;
        NSLog(@"in block %p", &x);          // 堆区
    };
    NSLog(@"定义后 %p", &x);                 // 堆区
   
    myBlock();
    NSLog(@"%d", x);
}

</pre><pre code_snippet_id="1656895" snippet_file_name="blog_20160421_3_7967570" name="code" class="objc">void demoBlock1() {
    int x = 10;
    NSLog(@"定义前 %p", &x);                 // 栈区
   
    // 提问:输出是多少?
    // 在定义block的时候,如果引用了外部变量,会对外部变量做一个copy,记录住定义block时变量的数值
    // 如果后续再修改x的值,不会影响block内部的数值变化!
    // 在默认情况下,不允许block内部修改外部变量的数值!因为会破坏代码的可读性,不易于维护!
    void(^myBlock)() = ^ {
        
//        x = 80;
       
        NSLog(@"%d", x);
        NSLog(@"in block %p", &x);          // 堆中的地址
    };
   
    NSLog(@"定义后 %p", &x);                 // 栈区
    x = 20;
   
    myBlock();
}

// block的定义
void demo() {
    // block定义的速记符号
    // inlineblock,能够快速敲出一个block的基本结构
    // 提示:block的定义必须要过关!
    // 如果记不住,可以用inlineblock辅助记忆,不要依赖inlneblock
   
    // 定义block
    /**
     定义时,把block当成数据类型
    
     特点:
     1. 类型比函数定义多了一个 ^
     2. 设置数值,有一个 ^,内容是 {} 括起的一段代码
    
     最简单的定义方式
     void (^myBlock)() = ^ { // 代码实现; }
     */
    void (^myBlock)() = ^ {
        NSLog(@"hello");
    };
   
    // 执行时,把block当成函数
    myBlock();
   
    // 定义带参数的block
    // 格式:void (^block名称)(参数列表) = ^ (参数列表) { // 代码实现; }
    void (^sumBlock)(int, int) = ^ (int x, int y) {
        NSLog(@"%d", x + y);
    };
   
    sumBlock(10, 20);
   
    // 定义带返回值的block
    // 格式:返回类型 (^block名称)(参数列表) = ^ 返回类型 (参数列表) { // 代码实现; }
    int (^sumBlock2)(int, int) = ^ int (int a, int b) {
        return a + b;
    };
   
    NSLog(@"%d", sumBlock2(4, 8));
}



// 如果要将block当作返回值,需要先单独定义一下block的类型
// 速记符号:typedefBlock
typedef void(^workBlock)();
使用block进行排序,效率非常高,以后替换掉for循环  
    // 1. 从iOS4开始,苹果封装了一系列块代码简化操作,提高效率
    // 1> 使用块代码遍历,效率比for in要高
    // 2> 把循环所需要的所有素材都以参数的形式提供了,可以直接使用
    [array enumerateObjectsUsingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop) {
        NSLog(@"%@", num);
       
        if (idx == 3) {
            *stop = YES;
        }
    }];
排序(效率比正常排还要高)
 NSArray *result = [array sortedArrayUsingComparator:^NSComparisonResult(NSNumber *num1, NSNumber *num2) {
//             compare 可以比较NSString,NSDate,NSNumber...
            // 升序
            return [num1 compare:num2];
            // 降序
            return [num2 compare:num1];
           
            // 乱序,随机的顺序=》一会升序,一会降序
            int seed = arc4random_uniform(2);
            if (seed == 1) {
                // 升序
                return [num1 compare:num2];
            } else {
                return [num2 compare:num1];
            }
        }];







注意点: 

一.   block 的反向传值
 
 1.
调用方:准备块代码
   
" 代理 " 来对比 - 类似于协议方法的实现
   
不同点:块代码都在一起,并没有单独的实现一个方法
 
 2.
被调用方:执行块代码
 1>    
要执行的代码:在 .h 中定义一个块代码的属性,又被称作 回调方法
 2>    
在需要的时候执行块代码!

 



  • 1 定义一个块代码的属性,block属性需要用copy
@property ( nonatomic , copy ) void (^completion)( NSString *text);
  • 2 给目标视图控制器传值(准备执行的块代码)
    // 目标视图控制器
    CZEditViewController *vc = segue. destinationViewController ;
    vc. completion = ^ ( NSString *str) {
       
self . nameLabel . text = str;
    };
  • 3 在执行之前,先判断块代码属性是否有内容
    if ( self . completion ) {
       
self . completion ( self . nameText . text );
    }



block陷阱

block 的陷阱-有可能会出现循环引用
 
 
解决办法:
 1.
要对内存对象之间的引用关系要清楚
 
技巧:
 1.
block 中碰到 self ,要格外小心, 有可能 会出现循环引用,通常最好思考一下
 2.
利用 dealloc 协助判断!如果不能被正常释放就说明有循环引用!
 

 *** block 在反向传值上有什么特点?
 
-简单
 
-所有代码都在一起,便于阅读,便于维护
 
 *** block & delegate
如何选择?
 
 
-如果回调方法比较少, 1 2 ,最好不要超过 3 个,这个时候使用 block 比较合适
 
-如果回调方法太多,会让代码显得臃肿,反而不好维护
 
 
-如果回调方法非常多,同时又不用每一个方法都必须实现,这个时候用 delegate 会比较方便!
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值