iOS - 初识 block

block定义

  • 格式:

返回类型 (^block名字) (参数列表);

  • 同C语言的定义函数指针一样,C语言的函数指针定义格式:

返回类型 (*指针名字) (参数列表);

block赋值

名字 = ^{xxx};

  • 如同普通的变量赋值一样类型、分号都需要‘一一对应’,如同int a = 5;^标志右边的代码段是block类型。

block调用

block名字 (参数列表);

例(无参):

//定义
 void (^valenti) ();
//赋值
 valenti = ^{
        NSLog(@"VaLenTi is MEEEEE!");
    };
//调用
 valenti();

例(有参):

//定义
 void (^valenti) (NSString* name);
//赋值
 valenti = ^(NSString* name){
        NSLog(@"VaLenTi is %@!",name);
    };
//调用
 valenti(@"ME");

例(有参有返回值):

//定义
 NSInteger (^sum)(NSInteger value1, NSInteger value2);
//赋值    
 sum = ^(NSInteger value1, NSInteger value2){
        return value1 + value2;
    };
//调用
 NSInteger result = sum(1,1);

typedef与block

如若有这样的需求:定义四个block实现两个参数的加减乘除,他们的代码是如下这样的:

    //加
    NSInteger (^add)(NSInteger value1, NSInteger value2);
    add = ^(NSInteger value1, NSInteger value2){
        return value1 + value2;
    };
    NSInteger result = add(1,1);
   
    //减
    NSInteger (^sub)(NSInteger value1, NSInteger value2);
    sub = ^(NSInteger value1, NSInteger value2){
        return value1 - value2;
    };
    NSInteger result2 = sub(1,1);
    
    //乘
    NSInteger (^mul)(NSInteger value1, NSInteger value2);
    mul = ^(NSInteger value1, NSInteger value2){
        return value1 * value2;
    };
    NSInteger result3 = mul(1,1);
    
    //除
    NSInteger (^div)(NSInteger value1, NSInteger value2);
    div = ^(NSInteger value1, NSInteger value2){
        return value1 / value2;
    };
    NSInteger result4 = div(1,1);

可见,除了block的名字和操作不同以外,其余的结构都是相同的,那么,相同的部分即可用typedef起别名的形式“抽取”出来。格式如下:

typedef 返回值类型 (^block名字) (参数列表)

  • 同C语言的函数指针别名一样,名称即代表别名。

上述代码可改为:

//1.在类扩展处定义别名
typedef NSInteger (^calculate) (NSInteger value1,NSInteger value2);
//2.在实现中定义对应功能的block代码并赋值
//加
calculate add = ^(NSInteger value1, NSInteger value2){
    return value1 + value2;
 };
 NSInteger result = add(1,1);
//减
calculate sub = ^(NSInteger value1, NSInteger value2){
    return value1 - value2;
};
NSInteger result2 = sub(1,1);
//乘
calculate mul = ^(NSInteger value1, NSInteger value2){
    return value1 * value2;
};
NSInteger result3 = mul(1,1);
//除
calculate div = ^(NSInteger value1, NSInteger value2){
    return value1 / value2;
};
NSInteger result4 = div(1,1);

注意事项

  1. block可以访问外部变量,例:
int a = 10;
void (^block)() = ^{
      NSLog(@"%zd",a);
}
  1. block中可以定义和外界同名的变量,在block内部外部存在同名变量的情况下,block访问的变量是内部变量-“就近原则”。

  2. 默认情况下,不可以在block内部修改外部的变量,1中block内部是不可以对a进行赋值的,因为block中的a和外部的a本质上并不是同一个a,block访问的外部变量会将外部的变量拷贝一份到堆内存中,验证:

int a = 5;
NSLog(@"%p",&a);
void (^block)()= ^{
      NSLog(@"%p",&a);
};
block();

结果是:

0x7fff53f42a2c
0x7fb601475220

  • 如果想在block中修改外界变量的值,必须在外界变量前面加上__block,在内部修改了变量的值会直接影响外部的值,但是内部外部的变量依然不是同一个,他们的内存地址依然不同
__block int a = 5;
NSLog(@"%p",&a);
void (^block)() = ^{
    a = 10;
    NSLog(@"%p",&a);
};
block();

结果是:

0x7fff5100ea88
0x7fe931629858

那么,加上__block就可以的本质原因就是传值方式的原因。

  1. 把未加__ block修饰的那段代码的ViewController.m的代码编译成C++代码,如图:
未加__block修饰的.cpp代码文件

画框代码即是核心部分,如下:


int a = 5;
    void (*block)() = ((void (*)())&__ViewController__viewDidLoad_block_impl_0((void *)__ViewController__viewDidLoad_block_func_0, &__ViewController__viewDidLoad_block_desc_0_DATA, a));
    ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);

历尽艰难险阻终于找到a的影子,其中__ViewController__viewDidLoad_block_impl_0是一个结构体,在这里传了三个参数:(void *)__ViewController__viewDidLoad_block_func_0&__ViewController__viewDidLoad_block_desc_0_DATAa,不难看出,这里是直接将a作为参数传递,也就是值传递,既然是值传递,修改里面的值对外部的a自然是无效的。

那么用__block修饰代码的cpp文件,就如下图:

用__block修饰的.cpp代码文件

画框部分是核心代码,如下:

 __attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 5};
    void (*block)() = ((void (*)())&__ViewController__viewDidLoad_block_impl_0((void *)__ViewController__viewDidLoad_block_func_0, &__ViewController__viewDidLoad_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
    ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);

仅仅加了一个修饰词,代码就有了不小的变动,这里的结构体传了四个参数,a在第三个位置,并且a也有了修饰:(__Block_byref_a_0 *)&a,不难看出,这里的&标志着这里是指针传递,既然是指针传递,修改里面的值肯定会影响到外部的那个变量。

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

推荐阅读更多精彩内容

  • 前言 Blocks是C语言的扩充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了这...
    小人不才阅读 3,759评论 0 23
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,134评论 30 470
  • 《Objective-C高级编程》这本书就讲了三个东西:自动引用计数、block、GCD,偏向于从原理上对这些内容...
    WeiHing阅读 9,804评论 10 69
  • iOS网络架构讨论梳理整理中。。。 其实如果没有APIManager这一层是没法使用delegate的,毕竟多个单...
    yhtang阅读 5,174评论 1 23
  • 有人说喜欢一个人是藏不住的,而最藏不住的应该是他看你的眼神吧,于千万人之中,第一眼看到的你,闪耀在他的眼眸...
    静默欢唱阅读 1,040评论 0 2