I'm using FSEvents to monitor a directory, and whenever the directory changes I call a block which I originally passed into the FSEventStreamContext of the FSEventStreamRef. How do I release the block when it is time to stop monitoring the directory? Code below for reference.
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);
}
FSEventStreamContext
has member variables for functions to retain and release the info
pointer, which in your example is your void *
block pointer.
Via Apple's FSEvents reference:
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.
First, retain. Since you need to cast the block to void *
for FSEventStreamContext
anyway, I think it's fine to continue using CFBridgingRetain()
in your startObserving:
method. No retain callback function is needed.
For release, try this callback function:
void release_callback(const void *info) {
CFBridgingRelease(info);
}
Then try changing your FSEventStreamContext
declaration to:
FSEventStreamContext context = { 0, ptr, NULL, release_callback, NULL };
That should release your block when stopObserving:
is called.