iOS Block -浅析 文章

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);

}

你可能感兴趣的:(iOS Block -浅析 文章)