OS X и FSEvents: как освободить указатель обратного вызова, предоставленный для FSEventStreamRef?

Я использую FSEvents для мониторинга каталога, и всякий раз, когда каталог изменяется, я вызываю блок, который я первоначально передал в FSEventStreamContext из FSEventStreamRef. Как освободить блок, когда пришло время прекратить мониторинг каталога? Код ниже для справки.

void fsevents_callback(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) {
    void (^block)() = (__bridge void (^)())(clientCallBackInfo);
    block();
}

- (FSEventStreamRef)startObserving:(NSString *)path block:(void(^)())block {
    void *ptr = (void *)CFBridgingRetain(block);  // NOTE: the block is retained
    FSEventStreamContext context = { 0, ptr, NULL, NULL, NULL };
    FSEventStreamRef stream = FSEventStreamCreate(NULL, fsevents_callback, &context, (__bridge CFArrayRef)@[path], kFSEventStreamEventIdSinceNow, 10, kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagIgnoreSelf);
    FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
    FSEventStreamStart(stream);
    return stream;
}

- (void)stopObserving:(FSEventStreamRef)stream {
    // HELP: the block should be released here. can I get it through FSEvents?
    FSEventStreamStop(stream);
    FSEventStreamInvalidate(stream);
    FSEventStreamRelease(stream);
}

1 ответ

Решение

FSEventStreamContext имеет переменные-члены для функций, чтобы сохранить и освободить info указатель, который в вашем примере ваш void * указатель блока

С помощью ссылки Apple на FSEvents:

retain
  The callback used retain the info pointer. This can be NULL.

release
  The callback used release a retain on the info pointer. This can be NULL.

Во-первых, сохранить. Так как вам нужно навести блок на void * за FSEventStreamContext во всяком случае, я думаю, что это нормально, чтобы продолжать использовать CFBridgingRetain() в вашем startObserving: метод. Не требуется сохранять функцию обратного вызова.

Для выпуска попробуйте эту функцию обратного вызова:

void release_callback(const void *info) {
    CFBridgingRelease(info);
}

Затем попробуйте изменить ваш FSEventStreamContext декларация для:

    FSEventStreamContext context = { 0, ptr, NULL, release_callback, NULL };

Это должно освободить ваш блок, когда stopObserving: называется.

Другие вопросы по тегам