iOS Block 介绍

来源:互联网 发布:高级sql生成选项 编辑:程序博客网 时间:2024/06/03 05:34

 前言 :Block 和GCD  是 iOS  多线程 编程的核心 ,它们是 一并引入的 ,Block 是一种可以在 C C++,Objective-C 当中使用的 语法闭包。开发者 可以将 代码像对象 一样传递。 令其在不同的 环境 下运行。还有一个很关键,就是 Block 在定义的范围内 可以访问到其中全部变量。 GCD 基于 dipatch queue .开发者将 线程排入队列中,由GCD 负责处理所有的事宜,其中包括 适时的创建,复用,销毁线程。 而开发者 不需要去处理。 这一点 不同于 Java 开发,开发者 需要自己去管理 线程。

一 : 简单介绍 Block

/**

 简单的 block

 */

- (void)simpleBlock

{

    // 语法结构 return_type (^block_name) (parameters)

    

    // 块其实就是个值而且自有其相关类型与 int float Objective-C 对象一样

    // 也可以把块赋给变量然后像使用其他变量那样使用它

    void (^someBlock)()=^{

        NSLog(@"this is a void return block");

    };

    

    int (^addBlock)(int a,int b)=^(int a,int b){

        return a+b;

    };

    

    int add=addBlock(2,5);

    NSLog(@"add is %d",add); // 7

    

    // block 强大之处在与声明它的范围里,所有变量都可以为其捕获

    int addtional = 5;

    int (^newAddBlock)(int a,int b)=^(int a,int b){

        return a+b+addtional;

    };

    

    int newAdd=newAddBlock(2,5);

    NSLog(@"newAdd is %d",newAdd);//  12

    

    // __block 修饰符这样可以在块内部修改 这个变量

    // 苹果的这个方法给我们 演示了内联块的用法

    NSArray *array=@[@0,@1,@2,@3,@4,@4];

    __blockNSInteger count=0;

    [array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx,BOOL * _Nonnull stop) {

        if ([objcompare:@2] == NSOrderedAscending){

            count++;

        }

    }];

    

    NSLog(@"count is %ld",(long)count);

    // count =2

    

}


#pragma mark ---- 使用typedef block


// 实际上这种定义Block 类型的使用block是我们主要使用block 的方式

typedef int (^EOCSomeBlock)(BOOL flag,int value);

- (void)typedefBlock

{

    // 使用typedef block 有两个好处 可以在使用块的时候更易用更易懂

    // 如果 哪天要修改 那么 我们只需要修改 EOCSomeBlock那么在所有之前调用过

    // EOCSomeBlock 的地方 编译器都会给我们报错,而如果我们写成 (int(^)(BOOL flag,int value))completion那么很 有可能会忘记具体的地方。

}



// 对比下面这两个方法哪个更好呢?

- (void)noTypedefBlock:(int(^)(BOOL flag,int value))completion

{

    

}


- (void)typedefBlock:(EOCSomeBlock )completion

{

    

}


#pragma mark ----  全局块栈块 以及堆块


/**

  block

定义 block 的时候其所占的内存区域是分配在栈中的。也就是说 block 只在定义它的那个范围内有效

 下面这个段代码就有危险,因为可以通过编译 但是运行时而错误时而正常 ,若编译器没有覆写待执行的代码

  则正常反之 崩溃。因为我们并不知道 stack 上面的内存啥时候会回收覆写

 */

- (void)testStackBlock

{

    void (^block)();

    int i=arc4random()%2;

    if (i==0) {

        block=^{

            NSLog(@" Block A i is %d",i);

        };

    }else{

        block=^{

            NSLog(@"Block B i is %d",i);

        };

    }

    

    block();

}



/**

  Block

 block对象发送  copy 消息后会把 block 拷贝到堆上面去了

 对一个block 后续的copy 不会真的执行复制 只是递增引用计数 ARC环境下会自动释放

 这样代码就真正安全了

 */

- (void)testCopyBlock

{

    void (^block)();

    int i=arc4random()%2;

    if (i==0) {

        block=[^{

            NSLog(@" Block A i is %d",i);

        } copy];

    }else{

        block=[^{

            NSLog(@"Block B i is %d",i);

        } copy];

    }

    

    block();

}


// 这是一个全局 block

// 全局block声明在全局内存里 ,不需要每次用到的时候在栈中创建

// 不会捕捉任何的外围的变量对全局块的拷贝操作是个空操作。 实际相当于一个单例

void (^block)()=^{

    NSLog(@"this is a block ");

};