objective-c – 在FSEventStream回调(ObjC和ARC)中丢失指针

我已成功获得FSEventStream的基础知识,允许我查看新文件事件的文件夹.不幸的是,我传入FSEventStreamCreate()的回调引用正在丢失/损坏/不保留,因此我无法访问我需要的数据对象.这是关键代码块:

FileWatcher.m :(设置FSEvent流)

FSEventStreamContext context;
//context.info = (__bridge_retained void *)(uploadQueue);  // this didn't help
context.info = CFBridgingRetain(uploadQueue);
context.version = 0;
context.retain = NULL;
context.release = NULL;
context.copyDescription = NULL;

/* Create the stream, passing in a callback */
stream = FSEventStreamCreate(NULL,
                             &FileWatcherCallback,
                             &context,
                             pathsToWatch,
                             kFSEventStreamEventIdSinceNow, /* Or a previous event ID */
                             latency,
                             kFSEventStreamCreateFlagFileEvents /* Also add kFSEventStreamCreateFlagIgnoreSelf if lots of recursive callbacks */
                             );

Filewatcher.m:FileWatcherCallback

void FileWatcherCallback(
                     ConstFSEventStreamRef streamRef,
                     FSEventStreamContext *clientCallBackInfo,
                     size_t numEvents,
                     void *eventPaths,
                     const FSEventStreamEventFlags eventFlags[],
                     const FSEventStreamEventId eventIds[])
{
    int i;
    char **paths = eventPaths;

    // Retrieve pointer to the download Queue!
    NSMutableDictionary *queue = (NSMutableDictionary *)CFBridgingRelease(clientCallBackInfo->info);
    // Try adding to the queue
    [queue setValue:@"ToDownload" forKey:@"donkeytest" ];
    ...
}

当触发此回调函数时,我可以正确地获取文件路径,但是指向NSMutableDictionary的clientCallBackInfo-> info指针现在指向与设置流时不同的内存地址.
当我尝试添加到字典中时,我会抛出一个异常(setValue行).

我是否需要以某种方式处理指针?任何帮助将非常感激.
(我在Xcode 4.5.1上使用包括ARC的默认构建设置.)

最佳答案 回调函数的第二个参数是void * info(它是context.info),而不是指向FSEventStreamContext上下文结构的指针.

所以这段代码应该能够获得正确的指针:

void FileWatcherCallback(
                         ConstFSEventStreamRef streamRef,
                         void *info, // <-- this is context.info
                         size_t numEvents,
                         void *eventPaths,
                         const FSEventStreamEventFlags eventFlags[],
                         const FSEventStreamEventId eventIds[])
{
    // ...
    // Retrieve pointer to the download queue:
    NSMutableDictionary *queue = CFBridgingRelease(info);
    // ...
}

备注:在我看来,使用CFBridgingRetain()/ CFBridgingRelease()还有另一个问题.每次调用回调函数时,uploadQueue对象的保留计数将递减.这会导致崩溃很快.

它可能更好用

context.info = (__bridge void *)(uploadQueue);

用于创建事件流,以及

NSMutableDictionary *queue = (__bridge NSMutableDictionary *)info;

在回调函数中.只要使用事件流,您只需确保对uploadQueue保持强引用.

点赞