Block学习总结(一)

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();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容