为什么使用块?
块对象封装单元——也许,在抽象的术语,一段代码,可以在任何时间执行。 从本质上说,他们是便携式和匿名函数,可以作为参数传递的方法和函数或从方法和函数可以返回。 块本身有一个类型参数列表和可能推断或声明的返回类型。 你也可以将一块分配给一个变量,然后就像一个函数调用它。
插入符号的符号(^)作为句法标记块。 例如,下面的代码声明了一个变量在两个街区整数并返回一个整数值。 它提供了参数列表在第二次插入符号和括号内的实现代码,并分配这些繁殖
变量:
int (^Multiply)(int, int) = ^(int num1, int num2) { |
return num1 * num2; |
}; |
int result = Multiply(7, 4); // Result is 28. |
作为方法或函数参数,块是一种回调,可能被视为一种代表团有限的方法或函数。 通过在一块,调用代码可以定制一个方法或函数的行为。 当被调用时,该方法或函数执行一些工作,在适当的时刻,返回到调用代码块的调用请求更多信息或获取特定于应用程序的行为。
块函数和方法参数的一个优势是,他们使调用者提供回调代码在调用。 因为这段代码不需要在一个单独的方法或函数实现,实现代码可以更简单、更容易理解。 需要通知的NSNotification
作为一个例子。 在“传统”的方法,一个对象添加本身作为观察员的通知,然后实现一个单独的方法(选择器的识别 addObserver:. .
方法)来处理通知:
- (void)viewDidLoad { |
[super viewDidLoad]; |
[[NSNotificationCenter defaultCenter] addObserver:self |
selector:@selector(keyboardWillShow:) |
name:UIKeyboardWillShowNotification object:nil]; |
} |
|
- (void)keyboardWillShow:(NSNotification *)notification { |
// Notification-handling code goes here. |
} |
与 addObserverForName:对象:队列:usingBlock:
方法你可以巩固notification-handling与方法调用代码:
- (void)viewDidLoad { |
[super viewDidLoad]; |
[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification |
object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { |
// Notification-handling code goes here. |
}]; |
} |
一个更有价值的块的优势超过其他形式的回调是股票数据块在当地的词法范围。 如果你实现一个方法,在这种方法定义一个块,块访问方法的局部变量和参数(包括堆栈变量)以及函数和全局变量,包括实例变量。 这种访问是只读的默认,但如果你声明一个变量 __block
修饰符,您可以更改其值在块内。 即使在方法或函数封闭块返回及其局部作用域被摧毁,局部变量存在的块对象只要有一个块的引用。
块在系统框架api
使用块一个显而易见的动机是,越来越多的系统框架采用块的方法和函数作为参数。 人能辨别六块左右的用例框架方法:
-
完成处理程序
-
通知处理程序
-
错误处理程序
-
枚举
-
视图动画和过渡
-
排序
接下来的章节描述了,每一个案件。 但在我们去之前,这里是一个快速概述在框架方法解释块声明。 考虑下面的方法 NSSet
类:
- (NSSet *)objectsPassingTest:(BOOL (^)(id obj, BOOL *stop))predicate |
块声明表明,方法传递到块(每个枚举项)一个动态类型的对象和一个按引用调用布尔值;块返回一个布尔值。 (这些参数和返回值实际上是什么 为 都包含在 枚举 )。 指定你的块时,首先插入符号( ^
)和括号的参数列表;遵循这一块代码本身,由括号封闭。
[mySet objectsPassingTest:^(id obj, BOOL *stop) { |
// Code goes here: Return YES if obj passes the test and NO if obj does not pass the test. |
}]; |
完成和错误处理程序
完成回调处理程序,允许客户端框架方法或函数时执行一些操作完成它的任务。 通常客户端使用处理程序完成自由州或更新用户界面。 几种框架方法让你实现完成处理程序块(而非代表团方法或通知处理程序)。
的 UIView
动画和视图类有几类方法转换,完成处理程序块的参数。 ( 视图动画和过渡 这些方法的概述)。 的例子中 清单1 - 1 显示的实现 animateWithDuration:动画:完成:
方法。 完成处理程序在这个例子中重置动画视图回其原始位置和透明度(阿尔法)值动画结束后几秒钟。
- (IBAction)animateView:(id)sender { |
CGRect cacheFrame = self.imageView.frame; |
[UIView animateWithDuration:1.5 animations:^{ |
CGRect newFrame = self.imageView.frame; |
newFrame.origin.y = newFrame.origin.y + 150.0; |
self.imageView.frame = newFrame; |
self.imageView.alpha = 0.2; |
} |
completion:^ (BOOL finished) { |
if (finished) { |
// Revert image view to original. |
self.imageView.frame = cacheFrame; |
self.imageView.alpha = 1.0; |
} |
}]; |
} |
有些框架方法错误处理程序,这是块参数类似于完成处理程序。 方法调用它们(和传递 NSError
对象)时,它不能完成的任务,因为一些错误条件。 您通常实现错误处理程序来告知用户错误。
通知处理程序
的 NSNotificationCenter
方法 addObserverForName:对象:队列:usingBlock:
让你实施通知处理程序在您设置的观察。 清单1 - 2 说明了如何调用这个方法,定义一个块处理程序的通知。 与通知处理器方法,一个 NSNotification
对象是通过的。 该方法还需要一个 NSOperationQueue
实例,所以您的应用程序可以指定一个块处理程序运行的执行上下文。
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { |
opQ = [[NSOperationQueue alloc] init]; |
[[NSNotificationCenter defaultCenter] addObserverForName:@"CustomOperationCompleted" |
object:nil queue:opQ |
usingBlock:^(NSNotification *notif) { |
NSNumber *theNum = [notif.userInfo objectForKey:@"NumberOfItemsProcessed"]; |
NSLog(@"Number of items processed: %i", [theNum intValue]); |
}]; |
} |