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 に答える