美文网首页
Block学习总结(一)

Block学习总结(一)

作者: cr7aa | 来源:发表于2016-12-18 16:53 被阅读0次

Block

Block作为日常开发中必备的一种开发技巧,通过日常的使用和学习,在此对 Block的基本概念,使用语法和 对于外部变量的使用三方面做一个学习总结。

1.什么是Blocks

什么是blocks,blocks是c语言的一种扩充功能。可以解释为“带有自动变量的匿名函数”。

匿名函数

匿名函数就是指没有名称的函数。正常的函数表达式一般为:

返回值类型 函数名 返回值 {

}
void func () {
    
}

而当我门需要调用这个函数时,是必须要知道函数名的。通常调用函数的方式有2种:

1 函数名()

2 函数指针的方式调用

// 1 函数名调用
   func();

// 2 函数指针调用
    void(*funcptr)() = &func;
    funcptr();

而blocks的函数表达式并没有带函数名:

^ 返回值 参数 {

}

^ void(){
        
};

把blocks赋值给block类型的参数

void(^blk)() = ^ void(){
        
};

调用blocks
blk();
或者
^ void(){
        
}();

可以发现blocks函数与常见的函数的区别 是没有了函数名和 最前面加上了** ^ *符号。而block类型的变量和函数指针的区别只是把函数指针的号换成了^。

截获自动变量

带有自动变量其实可以解释为能够截取自动变量的值。通常的变量类型有

  • 局部变量(自动变量)
  • 全局变量
  • 全局静态变量
  • 静态变量

能够在函数的多次调用的时候传递的变量值只有:

  • 全局变量
  • 全局静态变量
  • 静态变量
void test() {
     int a = 10;
     void(^blk)() = ^void(){
         printf("a = %d",a);
     };
     a = 20;
     blk();
}

函数最后的打印结果为*** a = 10 ***。到这里可以解释出blocks为带有(截获)自动变量i的匿名函数。

2.Block语法

block函数

关于block函数可以表示为 ^ 返回值类型 参数 表达式。

而以下4种方式也是可以的

1.^ 返回值类型 参数 表达式
    ^int(){
    
        return 1;
    };
     
2.^ 参数 表达式   (省略返回值类型)
    ^(){
        return 1;
    };

3.^ 返回值类型 表达式   (在没有参数的情况下省略参数)        
    ^int{
        return 1;
    };

4.^ 表达式   (返回值类型和参数 都可以省略)        
    ^{
        return 1;
    };

block类型的变量

在之前介绍过block类型的变量,将block函数可以赋值给block类型变量。它和函数指针十分相似。

// 函数指针
void func() {
    
}
void (*funcptr)() = &func;

//block类型变量    
void (^blk)() = ^{
    
    };

在日常开发中,我门会经常使用到block,关于block 它可以作为

  • block类型变量
  • 属性
  • 方法参数
  • 方法返回值
// 1 block作为变量
void (^blk)() = ^{
    
};

// 2 block作为属性
@property(nonatomic,copy) void(^blk)();

//3 block作为方法参数
- (void)methodUseBlock:(void (^)())blk {

}

//4 block作为方法返回值
- (void(^)())methodReturnBlock {

    return ^{};
}

平时为了更方便的使用block,将这种复杂的记述方式便于使用,可以借助typedef来使用block

typedef void (^blkType)();

通过使用typedef,再来看下实现之前的block场景

typedef void (^blkType)();

// 1 block作为变量
blkType blk = ^void(){
        
 };
 
// 2 block作为属性
@property(nonatomic,copy) blkType blk;

//3 block作为方法参数
- (void)methodUseBlock:(blkType)blk {
    
}

//4 block作为方法返回值
- (blkType)methodReturnBlock {

    return ^{};
}

平时方便查阅的话,可以到这里看下 http://fuckingblocksyntax.com/

3.截获的外部变量

保存定义时的值

在之前介绍block函数概念的时候,说了block能够截获外部变量。而且是在定义block函数的时候截获了外部的变量.对于局部变量来说在定义的block函数之后,改变局部变量的值。block内部使用的局部变量的值依然是block函数定义时的值。如下面的代码 函数最后的执行结果依然是 *** a = 10 ***.

void test() {
     int a = 10;
     void(^blk)() = ^void(){
         printf("a = %d",a);
     };
     a = 20;
     blk();
}

在block内部改变外部变量

如果block内部使用了外部变量,是不允许在block内部修改截获的变量的值的。所以下面的这段代码就是编译不过的。因为它改变了截获的外部变量a的值。

    int a = 10;
    void(^blk)() = ^{
        a = 20;
    };

但是下面的这段代码却是可以正常编译的。

    NSMutableArray *tempArray = [NSMutableArray array];
    void(^blk)() = ^{
    
        [tempArray arrayByAddingObject:[[NSObject alloc]init]];
    };

在这段代码中,blk确实截获了外部变量 tempArray这个数组,在block内部也向数组里增加了一个元素。为什么它能编译通过呢。其实block内部不允许改变截获的外部变量应该更严格的说是不允许改变外部变量的内存地址。

    NSMutableArray *tempArray = [NSMutableArray array];
    NSLog(@"原始的内存地址 %p",&tempArray);
    [tempArray arrayByAddingObject:[[NSObject alloc]init]];
    NSLog(@"添加元素后的内存地址 %p",&tempArray);
    
    打印结果
    2016-12-18 16:40:19.565 block[8358:803598] 原始的内存地址 0x7fff5778cac8
    2016-12-18 16:40:19.565 block[8358:803598] 添加元素后的内存地址      0x7fff5778cac8

可以看出内存地址并没有改变,而如果对对象进行赋值操作,则会和之前一样直接编译错误。因为改变了外部变量的内存地址。

    NSMutableArray *tempArray = [NSMutableArray array];
    void(^blk)() = ^{
    
        tempArray = [NSMutableArray arrayWithObjects:[[NSObject alloc]init], nil];
    };

__block说明符

既然在block内部无法直接修改截获的外部变量的值,而如果我门需要这样的功能的话,可以通过对外部变量加上 _ _ block修饰符则能实现在block内部修改外部变量的值。如下代码通过对外部变量a加上 _ _block 修饰符,就算在block内部修改了a的值,也能正常编译。

    __block int a = 10;
    void(^blk)() = ^{
        a = 20;
    };
    blk();

相关文章

  • Block学习总结一block分类

    Block分类 block定义的格式为: 返回值类型+block名+参数 以下是无参数定义 以下是有参数定义 bl...

  • Block学习总结(一)

    Block Block作为日常开发中必备的一种开发技巧,通过日常的使用和学习,在此对 Block的基本概念,使用语...

  • iOS 基础技术总结

    1.NSTimer 小结 感谢作者mgen的总结,学习了 2.__block和__weak区别 1.Block可以...

  • Block学习总结(三)

    关于block的存储域 一、 block变量存储域 1. ARC和MRC不同的存储情况 通过对block本质的探究...

  • Block学习总结(二)

    block 1.block的实质 之前说过其实block的本质就是"带有自动变量的匿名函数"。block类型的变量...

  • OC block 原理总结

    本文重点总结 OC block 的原理,并带上一些例子,不讨论 block 的写法和应用。 block 的本质总结...

  • iOS底层原理总结 - 探寻block的本质(一)

    iOS底层原理总结 - 探寻block的本质(一) iOS底层原理总结 - 探寻block的本质(一)

  • iOS Block 部分一

    主要讲解 Block 的底层实现原理; Block部分一Block部分二Block部分三Block知识点总结 基础...

  • Block学习总结一循环引用

    什么是循环引用 简单的说,就是我中有你,你中有我,虽然中华讲究阴阳共济,但是在内存中,这是不合理的。来一段例子 警...

  • iOS 之 block(4.4)

    本章主题,讨论 block 的嵌套 总结:可以看出block 被捕获,有 BLOCK_FIELD_IS_BLOCK...

网友评论

      本文标题:Block学习总结(一)

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