1.独立Block 2.内联Block
// 定义一个Block Object,返回值:NSString;别名:intToString;参数:NSUInteger。 NSString* (^intToString)(NSUInteger) = ^(NSUInteger paramInteger){ NSString *result = [NSString stringWithFormat:@"%lu",(unsignedlong)paramInteger]; return result; };
// 调用我们定义的Block Ojbect NSString *string = intToString(10); NSLog(@"string = %@", string);
typedef NSString* (^IntToStringConverter)(NSUInteger paramInteger);
- (NSString *)convertIntToString:(NSUInteger)paramInteger usingBlockObject:(IntToStringConverter)paramBlockObject{ return paramBlockObject(paramInteger); }
NSString *result = [self convertIntToString:123 usingBlockObject:intToString]; NSLog(@"result = %@", result);
typedef NSString* (^IntToStringConverter)(NSUInteger paramInteger);
- (NSString *)convertIntToString:(NSUInteger)paramInteger usingBlockObject:(IntToStringConverter)paramBlockObject{ return paramBlockObject(paramInteger); }
- (void) doTheConversion{ IntToStringConverter inlineConverter = ^(NSUInteger paramInteger){ NSString *result = [NSString stringWithFormat:@"%lu", (unsignedlong)paramInteger]; return result; }; NSString *result = [self convertIntToString:123usingBlockObject: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 = [NSStringstringWithFormat:@"%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();
输出:
2016-03-26 20:13:50.144 DemoVideo[20505:707] local integer = 10 2016-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", (unsignedlong)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); }