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];
}];

results matching ""

    No results matching ""