Как буферизировать входящие события / уведомления, которые отслеживает приложение iPhone, чтобы не вызывать код события для каждого события? - PullRequest
1 голос
/ 14 октября 2011

Каков наилучший способ буферизации входящих событий / уведомлений, которые отслеживает ваше приложение iPhone, чтобы не вызывать код события для каждого события? Пример кода был бы великолепен ...

например. было бы создать NSMutableArray в контроллере для добавления каждого события, и для каждого входящего в него события запускается время обратного отсчета в течение 2 секунд, так что обратный отсчет таймера вызовет код обработки событий ... в этом случае что было бы лучше всего использовать классы Objective-C для такого буфера / таймера / обратного отсчета ...

фон - в моем случае это события из "EKEventStoreChangedNotification", которые я обрабатываю, но отмечаю, что есть несколько, которые могут пройти при одном и том же изменении элемента календаря (насколько я могу судить)

Ответы [ 5 ]

2 голосов
/ 18 октября 2011

прикрепить объект к основному циклу выполнения (обычно через таймер).объект получает, собирает, фильтрует и объединяет события по мере необходимости.

что-то вроде этого будет отправной точкой (не скомпилировано):

@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

Теперь создайте таймер и добавьте егов основной цикл выполнения:

/* 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];
}
1 голос
/ 21 октября 2011

постановка в очередь и выполнение задач стало очень легко с GCD и блоком.

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

Просто общая идея.

1 голос
/ 18 октября 2011

В вашем объявлении ivar:

NSMutableArray *queuedEvents;

В реализации вашего класса:

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

Это буферизует до двух секунд событий перед их обработкой.

0 голосов
/ 22 октября 2011

Я не изучал, почему вы можете получать несколько событий EKEventStoreChangedNotification, и я не знаю, нормально ли это, но мой первый случай, когда я прочитал, что вы просто хотели отложить обработку на 2 секунды, звучал как kludge и должен быть лучший способ решить эту проблему.

Чтение документации Apple предполагает, что если вы не хотите обновлять, если это не является абсолютно необходимым, вам следует вызвать обновление, и только если это ДА, вы затем отпустите и перезагрузите все EKEvent объекты, которые вы сохранили. Мне кажется, что это гарантирует, что дублированные сообщения EKEventStoreChangedNotification не приведут к тому, что ваш код будет выполняться несколько раз, при условии, что ваш код в ответ на это обрабатывается в потоке, который получает уведомления (поэтому последующие уведомления не будут получены, пока код в ответ на первоначальный еще работает).

0 голосов
/ 20 октября 2011

Я не совсем понимаю ваш вопрос, но я предполагаю, что вы хотите запустить фильтр по событиям.

Существует довольно простой подход к этому с NSNotificationCenter.Мы опубликуем уведомление, затем установим некоторые параметры для свойства userInfo NSNotification, затем запустим уведомление через фильтр.

Сначала в .m файла, который будетотправка уведомления, куда уведомление должно быть отправлено:

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

Теперь в .m файла, который будет читать уведомление:

В init (или некоторыеинициализатор):

[[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;
}
...