IOS开发之---初识Block
1 // main.m 2 #import <Foundation/Foundation.h> 3 4 int main(int argc, const char * argv[]) { 5 @autoreleasepool { 6 // Declare the block variable 7 double (^distanceFromRateAndTime)(double rate, double time); 8 9 // Create and assign the block 10 distanceFromRateAndTime = ^double(double rate, double time) { 11 return rate * time; 12 }; 13 // Call the block 14 double dx = distanceFromRateAndTime(35, 1.5); 15 16 NSLog(@"A car driving 35 mph will travel " 17 @"%.2f miles in 1.5 hours.", dx); 18 } 19 return 0; 20 }
在上面的代码中,利用插入符(^)将distanceFromRateAndTime变量标记为一个block。就像声明函数一样,需要包含 返回值的类型,以及参数的类型,这样编译器才能安全的进行强制类型转换。插入符(^)跟指针(例如 int *aPointer)前面的星号(*)类似——只是在声明的时候需要使用,之后用法跟普通的变量一样。
1 double (^randomPercent)(void) = ^ { 2 return (double)arc4random() / 4294967295; 3 }; 4 NSLog(@"Gas tank is %.1f%% full", 5 randomPercent() * 100);
在上面的代码中,利用内置的arc4random()方法返回一个32位的整型随机数——为了获得0-1之间的一个值,通过除以arc4random()方法能够获取到的最大值(4294967295)。
1 NSString *make = @"Honda"; 2 NSString *(^getFullCarName)(NSString *) = ^(NSString *model) { 3 return [make stringByAppendingFormat:@" %@", model]; 4 }; 5 NSLog(@"%@", getFullCarName(@"Accord")); // Honda Accord
非局部变量会以const变量被拷贝并存储到block中,也就是说block对其是只读的。如果尝试在block内部给make变量赋值,会抛出编译器错误。
1 NSString *make = @"Honda"; 2 NSString *(^getFullCarName)(NSString *) = ^(NSString *model) { 3 return [make stringByAppendingFormat:@" %@", model]; 4 }; 5 NSLog(@"%@", getFullCarName(@"Accord")); // Honda Accord 6 7 // Try changing the non-local variable (it won‘t change the block) 8 make = @"Porsche"; 9 NSLog(@"%@", getFullCarName(@"911 Turbo")); // Honda 911 Turbo
1 __block NSString *make = @"Honda";
这将告诉block对非局部变量做引用处理,在block外部make变量和内部的make变量创建一个直接的链接(direct link)。现在就可以在block外部修改make,然后反应到block内部,反过来,也是一样。
1 __block int i = 0; 2 int (^count)(void) = ^ { 3 i += 1; 4 return i; 5 }; 6 NSLog(@"%d", count()); // 1 7 NSLog(@"%d", count()); // 2 8 NSLog(@"%d", count()); // 3
Block作为函数的参数
1 // Car.h 2 #import <Foundation/Foundation.h> 3 4 @interface Car : NSObject 5 6 @property double odometer; 7 8 - (void)driveForDuration:(double)duration 9 withVariableSpeed:(double (^)(double time))speedFunction 10 steps:(int)numSteps; 11 12 @end
1 // Car.m 2 #import "Car.h" 3 4 @implementation Car 5 6 @synthesize odometer = _odometer; 7 8 - (void)driveForDuration:(double)duration 9 withVariableSpeed:(double (^)(double time))speedFunction 10 steps:(int)numSteps { 11 double dt = duration / numSteps; 12 for (int i=1; i<=numSteps; i++) { 13 _odometer += speedFunction(i*dt) * dt; 14 } 15 } 16 17 @end
在下面的代码中,有一个main函数,在main函数中block定义在另一个函数的调用过程中。虽然理解其中的语法需要话几秒钟时间,不过这比起另外声明一个函数,再定义withVariableSpeed参数要更加直观。
1 // main.m 2 #import <Foundation/Foundation.h> 3 #import "Car.h" 4 5 int main(int argc, const char * argv[]) { 6 @autoreleasepool { 7 Car *theCar = [[Car alloc] init]; 8 9 // Drive for awhile with constant speed of 5.0 m/s 10 [theCar driveForDuration:10.0 11 withVariableSpeed:^(double time) { 12 return 5.0; 13 } steps:100]; 14 NSLog(@"The car has now driven %.2f meters", theCar.odometer); 15 16 // Start accelerating at a rate of 1.0 m/s^2 17 [theCar driveForDuration:10.0 18 withVariableSpeed:^(double time) { 19 return time + 5.0; 20 } steps:100]; 21 NSLog(@"The car has now driven %.2f meters", theCar.odometer); 22 } 23 return 0; 24 }
上面利用一个简单的示例演示了block的通用性。在iOS的SDK中有许多API都利用了block的其它一些功能。NSArray的 sortedArrayUsingComparator:方法可以使用一个block对元素进行排序,而UIView的 animateWithDuration:animations:方法使用了一个block来定义动画的最终状态。此外,block在并发编程中具有强大 的作用。
1 // Car.h 2 #import <Foundation/Foundation.h> 3 4 // Define a new type for the block 5 typedef double (^SpeedFunction)(double); 6 7 @interface Car : NSObject 8 9 @property double odometer; 10 11 - (void)driveForDuration:(double)duration 12 withVariableSpeed:(SpeedFunction)speedFunction 13 steps:(int)numSteps; 14 15 @end
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。