美文网首页
iOS开发笔记-有关Block

iOS开发笔记-有关Block

作者: 我是一只攻城狮_ifYou | 来源:发表于2016-11-14 15:25 被阅读18次

    1.Block简介:

    可以简单的理解,Block其实包含两个部分内容:

    1)Block执行的代码,这是在编译的时候已经生成好的;
    2)一个包含Block执行时需要的所有外部变量值的数据结构。 Block将使用到的、作用域附近到的变量的值建立一份快照拷贝到栈

    P.S. Block与函数的区别:

    Block可以访问函数以外、词法作用域以内的外部变量的值。换句话说,Block不仅 实现函数的功能,还能携带函数的执行环境

    2.Block的基本用法:

    // 声明一个Block变量
    long (^sum) (int, int) = nil;// sum是个Block变量,该Block类型有两个int型参数,返回类型是long。
    // 定义Block并赋给变量
    sumsum = ^ long (int a, int b) { return a + b;};
    // 调用Block:
    long s = sum(1, 2);
    

    为了看着比较顺眼,通常使用typedef进行定义

    typedef long (^block)(int, int);
    - (block) sumBlock { 
    int base = 100; 
    block blk = ^ long (int a, int b) {
     return base + a + b;
     } 
    return [[blk copy] autorelease];}
    

    Block在内存中的位置

    根据Block在内存中的位置分为三种类型NSGlobalBlock,NSStackBlock, NSMallocBlock。

    NSGlobalBlock:类似函数,位于text段;
    NSStackBlock:位于栈内存,函数返回后Block将无效;
    NSMallocBlock:位于堆内存。

    block blk1 = ^ long (int a, int b) { return a + b;};
    NSLog(@"blk1 = %@", blk1);// blk1 = <__NSGlobalBlock__: 0x47d0>
    int base = 100;
    block blk2 = ^ long (int a, int b) { return base + a + b;};
    NSLog(@"blk2 = %@", blk2); // blk2 = <__NSStackBlock__: 0xbfffddf8>BlkSum 
    blk3 = [[blk2 copy] autorelease];
    NSLog(@"blk3 = %@", blk3); // blk3 = <__NSMallocBlock__: 0x902fda0>
    

    blk1与blk2的区别在于:
    blk1没有使用block外的任何外部变量,Block不需要建立局部变量值的快照,这就使得blk1与函数没有任何的区别
    blk2使用了外部的变量base,在定义(注意是定义,不是运行)blk2时,局部变量base当前值被copy到栈上,作为常量供Block使用

    例:
     int base = 100; 
     base += 100;
     block sum = ^ long (int a, int b) {
     return base + a + b; 
    }; 
    base++;
    printf("%ld",sum(1,2));
    

    打印结果为:203
    在Block内变量base是只读的,如果想在Block内改变base的值,在定义base时要用:__block int base = 100;

    __block int base = 100; 
    base += 100; 
    BlkSum sum = ^ long (int a, int b) {
     base += 10; 
    return base + a + b;
     }; 
    base++; 
    printf("%ld\n",sum(1,2)); 
    printf("%d\n",base);
    

    打印结果为:214和211
    Block中使用__block修饰的变量时,将取变量此刻运行时的值,而不是定义时的快照

    Block的copy、retain、release操作

    不同于NSObjec的copy、retain、release操作:

    Block_copy与copy等效,Block_release与release等效;
    对Block不管是retain、copy、release都不会改变引用计数retainCount,retainCount始终是1;

    1)NSGlobalBlock:retain、copy、release操作都无效;
    2)NSStackBlock:retain、release操作无效,必须注意的是,NSStackBlock在函数返回后,Block内存将被回收。即使retain也没用。容易犯的错误是[[mutableAarry addObject:stackBlock],在函数出栈后,从mutableAarry中取到的stackBlock已经被回收,变成了野指针。正确的做法是先将stackBlock copy到堆上,然后加入数组:[mutableAarry addObject:[[stackBlock copy] autorelease]]。支持copy,copy之后生成新的NSMallocBlock类型对象。
    3)NSMallocBlock支持retain、release,虽然retainCount始终是1,但内存管理器中仍然会增加、减少计数。copy之后不会生成新的对象,只是增加了一次引用,类似retain;
    P.S尽量不要对Block使用retain操作。

    Block对不同类型的变量的存取

    基本类型

    局部自动变量,在Block中只读。Block定义时copy变量的值,在Block中作为常量使用,所以即使变量的值在Block外改变,也不影响他在Block中的值。

    static变量、全局变量。如果把上个例子的base改成全局的、或static。Block就可以对他进行读写了。因为全局变量或静态变量在内存中的地址是固定的,Block在读取该变量值的时候是直接从其所在内存读出,获取到的是最新值,而不是在定义时copy的常量。

    Block变量,被__block修饰的变量称作Block变量。 基本类型的Block变量等效于全局变量、或静态变量。

    Block被另一个Block使用时,另一个Block被copy到堆上时,被使用的Block也会被copy。但作为参数的Block是不会发生copy的

    本文具体参考:http://blog.csdn.net/wildfireli/article/details/21979955

    相关文章

      网友评论

          本文标题:iOS开发笔记-有关Block

          本文链接:https://www.haomeiwen.com/subject/hrmhpttx.html