次の2つのクラスがあります。
イベントディスパッチャー:
@interface EventDispatcher()
-(id)initEventDispatcher;
-(NSMutableArray*)getSubscriptionsToEvent:(EVENT_TYPE)eventType;
-(NSNumber*)getKeyToEvent:(EVENT_TYPE)eventType;
@end
@implementation EventDispatcher
static EventDispatcher* eventDispatcher;
// Singleton.
+(EventDispatcher*)instance
{
if (eventDispatcher == nil)
{
eventDispatcher = [[EventDispatcher alloc] initEventDispatcher];
}
return eventDispatcher;
}
-(id)initEventDispatcher
{
self = [super init];
if (self)
{
eventSubscriptions = [[NSMutableDictionary alloc] init];
}
return self;
}
// Let anyone subscribe to an event. Return the EventSubscriber so they can dispatch events if needed, and to be able to unsubscribe.
-(EventSubscriber*)subscribe:(EVENT_TYPE)eventType :(void(^)(id package))operateEvent
{
// Create the object.
EventSubscriber* eventSubscriber = [[EventSubscriber alloc] initEventSubscriber:eventType :operateEvent];
// Now get the list it belongs to (we sort subscriptions in a dictionary so that when we dispatch an event, it's fast (we don't need to iterate through all EventSubscribers to find who subscribe to an event).
NSMutableArray* subscriptionsToThisEvent = [self getSubscriptionsToEvent:eventType];
if(subscriptionsToThisEvent == nil)
{
// If the list is nil, no one has subscribed to it yet, so make that list and add it to the dictionary.
subscriptionsToThisEvent = [[NSMutableArray alloc] init];
NSNumber* key = [self getKeyToEvent:eventType];
[eventSubscriptions setObject:subscriptionsToThisEvent forKey:key];
[subscriptionsToThisEvent release];
}
// Add the EventSubscriber to the subscription list.
[subscriptionsToThisEvent addObject:eventSubscriber];
[eventSubscriber release];
return eventSubscriber;
}
-(void)unsubscribe:(EventSubscriber*)eventSubscriber
{
// Get the list it belongs to, and remove it from that list.
EVENT_TYPE eventType = [eventSubscriber getEventType];
NSMutableArray* subscriptionsToThisEvent = [self getSubscriptionsToEvent:eventType];
if (subscriptionsToThisEvent != nil)
{
[subscriptionsToThisEvent removeObject:eventSubscriber];
}
}
-(void)dispatch:(EVENT_TYPE)eventType :(id)package
{
NSMutableArray* subscriptionsToThisEvent = [self getSubscriptionsToEvent:eventType];
// If no one has subscribed to this event, it could be nil, so do nothing.
if (subscriptionsToThisEvent != nil)
{
// Otherwise, let them all know that the event was dispatched!
for (EventSubscriber* eventSubscriber in subscriptionsToThisEvent)
[eventSubscriber dispatch:package];
}
}
// Helper methods to get stuff (lists, keys) from event types.
-(NSMutableArray*)getSubscriptionsToEvent:(EVENT_TYPE)eventType
{
NSNumber* key = [self getKeyToEvent:eventType];
NSMutableArray* subscriptionsToThisEvent = [eventSubscriptions objectForKey:key];
return subscriptionsToThisEvent;
}
-(NSNumber*)getKeyToEvent:(EVENT_TYPE)eventType
{
return [NSNumber numberWithInt:eventType];
}
-(void)dealloc
{
[eventSubscriptions release];
[super dealloc];
}
@end
EventSubscriber:
#import "EventSubscriber.h"
@implementation EventSubscriber
-(id)initEventSubscriber:(EVENT_TYPE)newEventType :(void(^)(id package))newOperateEvent
{
self = [super init];
if (self)
{
operateEvent = [newOperateEvent copy];
eventType = newEventType;
}
return self;
}
-(void)dispatch:(id)package
{
operateEvent(package);
}
-(EVENT_TYPE)getEventType
{
return eventType;
}
-(void)dealloc
{
[operateEvent release];
[super dealloc];
}
@end
大きな問題: このシステムを使用しているプログラマーが、割り当て解除中にイベントから退会しなければならないという負担を軽減するにはどうすればよいでしょうか? 複数のクラスがこのシステムを使用している場合、プログラマーは割り当て解除中に忘れずにサブスクライブを解除する必要があります (以前でなければ)。 、デバッグ可能なクラッシュですが、前者の方がよりそうです)。理想的には、オブジェクトの割り当てが解除されたときに EventDispatcher がそれを適切に処理できるように、このシステムを再構築 (または何かを実行) したいと考えています。
簡単な解決策の 1 つは、オブジェクトに EventSubscriber を直接割り当てるようにし、次に EventSubscriber コンストラクターで、それ自体を EventDispatcher にサブスクライブすることです (しかし、これは明らかに悪いことです。EventDispatcher のものを静的にすることもできますか? うーん、さらに悪化しています)。
補足:
私は ARC を使用していませんが、それはここでは問題ではありません (少なくとも、ARC ベースのソリューションがあれば、それを聞きたいと思います)。
サブスクリプションを行った人が EventSubscribers を削除できるように、EventDispatcher にメソッドを追加する予定です (したがって、サブスクライブするとき、オブジェクトは「self」を渡す必要があります)。列挙された EVENT_TYPE で文字列を使用することも計画していますが、それはまったく別のトピックです。
また、多くのコード (これらのクラスを含む) を C++ に翻訳する予定です。したがって、Objective-C 固有のソリューションとは対照的に、概念的なソリューションに感謝します。
それで、これは可能ですか?
本当にありがとう!