Block 如何代替了Delegate
要了解在哪些场合使用block,我们不妨先看一下苹果自己如何使用block。
首先是UIView 动画。当我们在某个view 上面改变了某些subview 的位置与大小,或是改变了这个view 的一些属性,像是背景颜色等,一般来说不会产生动画效果,我们的改动会直接生效,但是我们也可以产生一段动画效果,这种动画我们称为UIView Animation。(UIView Animation 其实底层是透过Core Animation 完成的,但我们稍晚才会讨论Core Animation。)
像是,我们想要改动某个subview 的frame:
self.subview.frame = CGRectMake(10, 10, 100, 100);
在iOS 4之前,我们会使用UIView的+beginAnimations:context:
与+commitAnimations
两个class method,把原本的code包起来,那么,在这两个class method之间的代码就会产生动画效果。
[UIView beginAnimations:@"animation" context:nil];
self.subview.frame = CGRectMake(10, 10, 100, 100);
[UIView commitAnimations];
如果我们想要在这段动画结束的时候做一件事情,像是执行另外一个动画,我们应该怎么做呢?iOS 4 之前唯一的方法就是透过UIView 的delegate,我们在执行动画之前,需要先设定好delegate,以及要执行delegate 上的哪个selector。像是:
- (void)moveView
{
[UIView beginAnimations:@"animation" context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:
@selector(animationDidStop:finished:context:)];
self.subview.frame = CGRectMake(10, 10, 100, 100);
[UIView commitAnimations];
}
- (void)animationDidStop:(NSString *)animationID
finished:(NSNumber *)finished
context:(void *)context
{
// do something
}
可以看到,如果使用delegate pattern,一段连续的流程,会分散在很多不同的method 中。有了block 语法之后,我们可以将「动画该做什么」与「动画完成之后要做什么」,写成一段集中的程式码。像是:
- (void)moveView
{
[UIView animateWithDuration:0.25 animations:^{
self.subview.frame = CGRectMake(10, 10, 100, 100);
} completion:^(BOOL finished) {
// Do something
}];
}
另外像NSArray 里头的物件排序,以往我们必须以C function pointer 或是selector 形式传入用来比较实例大小的comparator。像是:
NSArray *array = @[@1, @2, @3];
NSArray *sortedArray = [array sortedArrayUsingSelector:@selector(compare:)];
也可以改用block 语法:
NSArray *array = @[@1, @2, @3];
NSArray *sortedArray = [array sortedArrayUsingComparator:
^NSComparisonResult(id obj1, id obj2) {
return [obj1 compare:obj2];
}];