开发者

how to buffer incoming events/notifications your iPhone app is observing so as not to trigger event code for each event?

What is the best way to buffer incoming events/notifications your iPhone app is observing so as not to trigger event code for eac开发者_运维百科h event? A code sample would be great...

e.g. would it be to create an NSMutableArray in the controller to add each event to, and for each event that comes in it triggers a count down time for 2 seconds, so the timer countdown would trigger the events handling code...in which case what would be the best Objective-C classes to use for such a buffer/timer/countdown...

background - in my case it the events from "EKEventStoreChangedNotification" that I handle, but noting there are multiple that can come through for the same single calendar item change (well as far as i can tell)


attach an object to your main run loop (typically via a timer). the object receives, collects, filters, and coalesces the events as needed.

something like this would be a starting point (not compiled):

@interface MONEventHandler : NSObject
{
    NSMutableArray * events;
    NSRecursiveLock * lock;
}

@end

@implementation MONEventHandler

- (id)init
{
    self = [super init];
    if (nil != self) {
        events = [NSMutableArray new];
        lock = [NSRecursiveLock new];
        /* begin listening for incoming events */
    }
    return self;
}

- (void)dealloc
{
/* stop listening for incoming events */
    [lock release], lock = nil;
    [events release], events = nil;
    [super dealloc];
}

- (void)postEvents:(NSTimer *)timer
{
    [lock lock];
    /* ... clear out self.events here ... */
    [lock unlock];
}

/* a few methods for your event entries, or callbacks */

@end

Now create the timer and add it to the main run loop:

/* call me on main thread ONLY */
void SetupEventHandler() {
    MONEventHandler * eventHandler = [MONEventHandler new];
    NSTimeInterval seconds = 0.100; /* 10Hz */
    NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:seconds target:eventHandler selector:@selector(postEvents:) userInfo:nil repeats:YES];
    /* you will need timer if you want to explicitly stop updates or destroy eventHandler. you do this by invalidating the timer. you can also access it from postEvents: */
   [eventHandler release];
}


In your ivar declaration:

NSMutableArray *queuedEvents;

In your class implementation:

- (void)queueEvent:(id)event
{
    if (!queuedEvents) {
        queuedEvents = [[NSMutableArray alloc] init];
        [self performSelector:@selector(processQueuedEvents) withObject:nil afterDelay:2.0];
    }
    [queuedEvents addObject:event];
}

- (void)processQueuedEvents
{
    NSArray *events = queuedEvents;
    queuedEvents = nil;
    for (id event in events) {
        // Do something with event
    }
    [events release];
}

This will buffer up to two seconds of events before processing them.


queuing and execution of tasks became very easy with GCD and block.

-(void) delayHandler:(NSNotification *)notif {
   // check if notif is already on the event queue
   for (NSNotification *note in self.eventqueue) {
       if (note == notif) // use proper compare function, this is just a pointer compare
          return;
   }
   [self.eventqueue addObject:notif];

   dispatch_queue_t queue = self.handlerQueue;
   dispatch_time_t delay;delay = dispatch_time(DISPATCH_TIME_NOW, 50000 /* 50μs */);
   dispatch_after(delay, queue, ^{ 
      //event handling code here
      for (NSNotification *note in self.eventqueue) {
         // handle note in any way
         [self.eventqueue removeObject note];
      }
   );
}

Just a general idea.


I don't quite understand your question, but I assume that you want to run a filter on events.

There's a pretty straightforward approach to this with NSNotificationCenter. We'll be posting a notification, then setting some parameters on the userInfo property of NSNotification, then running the notification through a filter.

First, in the .m of the file that will be sending the notification, where the notification should be sent:

NSNotification *notification = [NSNotification notificationWithName:@"notification" 
                                                             object:self
                                                           userInfo:[NSDictionary dictionaryWithObject:someFilterObject
                                                                                                forKey:@"object"]];
[[NSNotificationCenter defaultCenter] postNotification:notification];

Now, in the .m of the file that will be reading the notification:

In init (or some initializer):

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(filterNotification:)
                                             name:@"notification"
                                           object:/* the object that sends the notification */];

In filterNotification:(NSNotification *)notification:

if ([[notification.userInfo objectForKey:@"object"] isEqual:desiredObject]) {
    // Do something
} else {
    return;
}


I have not looked into why you might be getting multiple EKEventStoreChangedNotification events, and I don't know if that is normal—but my first though when I read that you just wanted to delay processing by 2 seconds was that sounded like a kludge and there must be a better way to solve this.

Reading the Apple documentation it suggests that if you do not wish to update unless it is absolutely necessary to do so, you should call a refresh and only if this is YES would you then release and reload all EKEvent objects that you were retaining. It seems to me that this would ensure that duplicate EKEventStoreChangedNotification messages would not result in your code running multiple times, providing your code in response to this is processed on the thread that is receiving the notifications (so subsequent notifications are not being received while the code in response to the initial one is still running).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜