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:
называется.