浅谈 Block 基本使用

原文链接 http://blog.sina.com.cn/s/blog_7b9d64af0101c4sh.html
Block 的使用有两种:1.独立Block 。2.内联Block 。

《一》独立Block 使用方式

一、定义一个Block Object,并调用。

1.定义

// 定义一个Block Object,返回值:NSString;别名:intToString;参数:NSUInteger。

NSString* (^intToString)(NSUInteger) = ^(NSUInteger paramInteger){
    NSString *result = [NSString stringWithFormat:@"%lu",(unsigned long)paramInteger];
    return result;
};

2.调用

// 调用我们定义的Block Ojbect
NSString *string = intToString(10);
NSLog(@"string = %@", string);

二、将Block Object 当作参数,在方法之间传递,调用。

有时候,我们希望将定义的Block Object作为函数的参数使用,就像其他的数据类型一样。

1.为Block Object 定义签名

typedef NSString* (^IntToStringConverter)(NSUInteger paramInteger);

这就告诉,编译器,我们定义了一个签名(别名)为IntToStringConverter 的Block Object。这个Block返回值为:NSString;参数为:NSUInteger。

2.定义使用Block为参数的函数

- (NSString *)convertIntToString:(NSUInteger)paramInteger usingBlockObject:(IntToStringConverter)paramBlockObject{
    
    return paramBlockObject(paramInteger);
}

这一步,很简单,我们将前面定义的Block作为了一种类型。这种类型为:IntToStringConverter

3.调用使用Block为参数的方法

 NSString *result = [self convertIntToString:123 usingBlockObject:intToString];
    NSLog(@"result = %@", result);

调用时,123,和intToString可理解为实参。

《二》内联Block 使用方式

在此之前,让我们梳理一下需要的代码:

1.定义

typedef NSString* (^IntToStringConverter)(NSUInteger paramInteger);

2.用Block作为参数的函数

- (NSString *)convertIntToString:(NSUInteger)paramInteger usingBlockObject:(IntToStringConverter)paramBlockObject{
    
    return paramBlockObject(paramInteger);
}

3.内联调用

- (void) doTheConversion{
    IntToStringConverter inlineConverter = ^(NSUInteger paramInteger){
        NSString *result = [NSString stringWithFormat:@"%lu", (unsigned long)paramInteger];
        return result;
    };
    
    NSString *result = [self convertIntToString:123 usingBlockObject:inlineConverter];
    NSLog(@"result = %@", result);
    
}

调用的时候,只需要这样:
[self doTheConversion];

什么是内联Block?
我的理解是,写在方法内部的,编译器在编译阶段无法知道要调用的具体Block内容。
就像上边的例子:
独立Block:在编译阶段,已经就定义好了Block方法:

// 定义一个Block Object,返回值:NSString;别名:intToString;参数:NSUInteger。

NSString* (^intToString)(NSUInteger) = ^(NSUInteger paramInteger){
    NSString *result = [NSString stringWithFormat:@"%lu",(unsigned long)paramInteger];
    return result;
};

内联Block:在编译阶段,编译器并不知道所关联的Block是什么。
因为它是在调用doTheConversion方法时,临时分配的(inlineConverter)。红色块。

- (void) doTheConversion{
   IntToStringConverter inlineConverter = ^(NSUInteger paramInteger){
       NSString *result = [NSString stringWithFormat:@"%lu", (unsignedlong)paramInteger];
       return result;
   };
   
   NSString *result = [self convertIntToString:123 usingBlockObject:inlineConverter];
   NSLog(@"result = %@", result);
   
}

同理,就相当于:


- (void) doTheConversion{
  
    NSString *result =[self convertIntToString:123
                              usingBlockObject:^(NSUInteger paramInteger) {
                                  NSString *result = [NSString stringWithFormat:@"%lu",(unsigned long)paramInteger];
                                  return result;
                              }];
   
   NSLog(@"result = %@", result);

}

是啊,很多iOS中的方法,用的都是这种方式!对用的就是内联Block!!!
原来如此啊!

先mark到这里吧!

下一步,我们来了解一下,关于Block变量的一些东西!

Block 的变量

1.独立Block 变量的操作。

定义Block:

void (^independentBlockObject)(void) = ^(void){
   NSInteger localInteger = 10;
   NSLog(@"local integer = %ld", (long)localInteger);
   localInteger = 20;
   NSLog(@"local integer = %ld", (long)localInteger);

};

调用:

independentBlockObject();

输出:

2013-03-26 20:13:50.144 DemoVideo[20505:707] local integer = 10
2013-03-26 20:13:50.147 DemoVideo[20505:707] local integer = 20

2.内联Block 变量的操作。

我们知道Object-C中已经有很多用Block作为参数的函数。该Block参数,作为内联Block调用。
于是,就用一个数组比较的方法:

定义:

- (void) simpleMethod{
    NSMutableArray *array = [[NSMutableArray alloc]initWithObjects:@"100",@"200",@"150", nil];
    
    NSArray *sortedArray = [array sortedArrayUsingComparator: ^(id obj1, id obj2) {
        
        if ([obj1 integerValue] > [obj2 integerValue]) {
            return (NSComparisonResult)NSOrderedDescending;
        }
        
        if ([obj1 integerValue] < [obj2 integerValue]) {
            return (NSComparisonResult)NSOrderedAscending;
        }
        return (NSComparisonResult)NSOrderedSame;
    }];
    
}

调用:

[self simpleMethod];

输出:

Printing description of sortedArray:
<__NSArrayI 0x1f56d430>(
100,
150,
200
)
Printing description of array:
<__NSArrayM 0x1f585ed0>(
100,
200,
150
)

我们不用关心,sortedArrayUsingComparator方法的内部实现是什么,但是,它在运行中,调用了内部变量:obj1和obj2

可见:独立Block可以在内部定义变量,访问变量,修改变量!

Block可以读写自己内部的变量,那么对于外部变量,有如何呢 ?

不着急,我们先来归纳一下用于测试的相关代码:
定义Block签名

typedef NSString* (^UserMyBlockFun)(NSUInteger paramInteger);
定义Block为参数的函数

- (NSString *)convertIntToString:(NSUInteger)paramInteger usingBlockObject:(UserMyBlockFun)paramBlockObject{
   
   return paramBlockObject(paramInteger);
}

定义调用函数:

- (void) doTheConversion{
   
   __block int outsideVariable=6;
   
   NSString *result =[self convertIntToString:123
                             usingBlockObject:^(NSUInteger paramInteger) {
                                 // 访问self
                                 NSLog(@"self = %@", self);
                                 // 访问self的实体变量
                                 NSLog(@"self = %@", self.strName);
                                 
                                 int insideVariable=10;
                                 insideVariable+=5;
                                 
                                 // 输出内部变量,没问题,对内部变量可读写
                                 NSLog(@"insideVariable:%d",insideVariable);
                                 // 输出外部变量,可以读取外部变量,但是不能修改,否则将报出一个错误。
                                 // Variable is not assignable(missing __block type specifier)
                                 NSLog(@"outSideVariable:%d",outsideVariable);
                                 
//                                  outsideVariable+=3;
                                 
                                 NSLog(@"outSideVariable:%d",outsideVariable);
                                 
                                 NSString *result = [NSString stringWithFormat:@"%lu",(unsigned long)paramInteger];
                                 return result;
                             }];
   
   NSLog(@"result = %@", result);
   
}

可见,对于外部普通变量,Block只有读取的权限。
但是,从一个错误:Variable is not assignable(missing __block type specifier)中,也许我们可以知道,

如果,要对外部变量具有写权限,那么就要在变量前,加上“__block”

__block int outsideVariable=6;
这样,就可以读写outsideVariable变量了。

内联Block可以直接访问self;但是,独立Block不能直接访问self,替代方式为,将self作为参数,传递给Block。

如:

// 独立Block

void (^correctBlockObject)(id) = ^(id self){
    // 将self作为参数传递
    NSLog(@"self = %@", self);
    // 访问self变量
    NSLog(@"self = %@", [self strName]);
    
};

- (void) callCorrectBlockObject{
    correctBlockObject(self);
}

有一点非常重要:

内联Block,调用的外部变量,使用的是复制方式。

运行一下,查看输出就知道了:

- (void) scopeTest{
   NSUInteger integerValue = 10;
   // 定义内联Block
   BlockWithNoParams myBlock = ^{
       NSLog(@"Integer value inside the block = %lu", (unsigned long)integerValue);
   };
   
   integerValue = 20;
   // 调用Block
   myBlock();
   NSLog(@"Integer value outside the block = %lu",(unsigned long)integerValue);

}

如果要使用引用方式,那么就要在变量前加上“ __block”

调用 Block

关于内联Block,因为其就是写在方法内的,所以,调用起来相对方便。就像iOS中的API,有很多方法,使用了内联Block方式。

关于独立Block,主要使用C语言的函数调用方式。

用例子来说明吧。

1.调用Block

// 定义Block
void (^simpleBlock)(NSString *) = ^(NSString *theParam){
   NSLog(@"the string=%@",theParam);
   
};
// 调用Block
- (void) callSimpleBlock{
   simpleBlock(@"O'Reilly");
}

2.嵌套调用

// 定义内层Block
NSString *(^trimString)(NSString *) = ^(NSString *inputString){
   NSString *result = [inputString stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
   return result;
};
// 定义外层Block
NSString *(^trimWithOtherBlock)(NSString *) = ^(NSString *inputString){
   return trimString(inputString);
};

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

推荐阅读更多精彩内容

  • Block 的使用有两种:1.独立Block 。2.内联Block 。 《一》独立Block 使用方式 一、定义一...
    乡村小子阅读 280评论 0 0
  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,047评论 9 119
  • 《Objective-C高级编程》这本书就讲了三个东西:自动引用计数、block、GCD,偏向于从原理上对这些内容...
    WeiHing阅读 9,728评论 10 69
  • 沉默时,我就系一颗风铃 如今这风声荡过远洋 天黑时,我就种一点星星 如今这森林荧光满树 寂寞时,我就铺一朵浪花 如...
    ___零点阅读 348评论 16 22
  • 最近这几天的现当代文学课让我感受到了,文学的力量。鲁迅是文学界最具代表的人物之一,他的《呐喊》与《彷徨》是现代小说...
    一孤月阅读 14,526评论 1 55