Block 与Delegate 都可以想成是Event Handler
我们在前一章当中提到,Objective-C 里头的delegate 其实相当于C# 里头event handler 的角色,但C# 里头的event handler 在语法上会更接近Objective-C 的block,都是匿名函数。
我们可以来看一个来自MSDN的例子.aspx) 。以下的C#程式中,有一个叫做Changed
的event handler。
sing System;
namespace MyCollections
{
using System.Collections;
// A delegate type for hooking up change notifications.
public delegate void ChangedEventHandler(object sender, EventArgs e);
// A class that works just like ArrayList, but sends event
// notifications whenever the list changes.
public class ListWithChangedEvent: ArrayList
{
// An event that clients can use to be notified whenever the
// elements of the list change.
public event ChangedEventHandler Changed;
// Invoke the Changed event; called whenever list changes
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}
// Override some of the methods that can change the list;
// invoke event after each
public override int Add(object value)
{
int i = base.Add(value);
OnChanged(EventArgs.Empty);
return i;
}
public override void Clear()
{
base.Clear();
OnChanged(EventArgs.Empty);
}
}
}
如果写成Objective-C 并且使用delegate,会像这样:
@class ListWithChangedEvent
@protocol ListWithChangedEventDelegate <NSObject>
- (void)listDidChange:(ListWithChangedEvent *)list args:(EventArgs *)e;
@end
@interface ListWithChangedEvent : NSObject
@property (weak, nonatomic) id <ListWithChangedEventDelegate> delegate;
@end
@implementation ListWithChangedEvent
- (void)onChanged:(EventArgs *)e
{
[self.delegate listDidChange:self args:e];
}
- (void)add:(id)value
{
[super add:value];
[self onChanged:nil];
}
- (void)clear:(id)value
{
[super clear:value];
[self onChanged:nil];
}
@end
那如果是block 呢?可以发现,会更接近C# 里头的写法了。
typedef void (^changedEventHandler)(id, EventArgs *);
@interface ListWithChangedEvent : NSObject
@property (copy, nonatomic) changedEventHandler changed;
@end
@implementation ListWithChangedEvent
- (void)onChanged:(EventArgs *)e
{
if (self.changed) {
self.changed(self, e);
}
}
- (void)add:(id)value
{
[super add:value];
[self onChanged:nil];
}
- (void)clear:(id)value
{
[super clear:value];
[self onChanged:nil];
}
@end
还是顺道一提,在C# 里头,我们可能会把所有的callback 都叫做event,但是在Cocoa 与Cocoa Touch 的世界里头,我们只会把来自硬件的输入叫做event。
由于block的主要用途,就在于处理callback,所以block经常就用在各种非同步工作的callback上,要执行各种非同步的工作,就往往要使用thread,关于在iOS与Mac上如何使用thread,我们将会在Threading这章中讨论。