0

我正在使用 FSEvents 来监视目录,并且每当目录更改时,我都会调用一个块,该块最初传递到 FSEventStreamRef 的 FSEventStreamContext 中。在停止监视目录时如何释放块?下面的代码供参考。

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);
}
4

1 回答 1

0

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 *为 for FSEventStreamContext,我认为可以继续CFBridgingRetain()在您的startObserving:方法中使用。不需要保留回调函数。

对于发布,试试这个回调函数:

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

然后尝试将您的FSEventStreamContext声明更改为:

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

这应该在stopObserving:被调用时释放你的块。

于 2013-11-01T12:38:59.267 回答