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这章中讨论。

results matching ""

    No results matching ""