【问题标题】:Pointer lost in FSEventStream Callback (ObjC and ARC)指针在 FSEventStream 回调中丢失(ObjC 和 ARC)
【发布时间】:2012-11-29 14:51:24
【问题描述】:

我已经成功地掌握了 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。)

【问题讨论】:

  • @Steen:你应该接受 Martin R 的回答,或者解释为什么这不能解决你的问题

标签: objective-c callback automatic-ref-counting nsmutabledictionary


【解决方案1】:

回调函数的第二个参数是void *info(即context.info),而不是指向FSEventStreamContext context结构的指针。

所以这段代码应该可以得到正确的指针:

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 的强引用。

【讨论】:

    【解决方案2】:

    我从来没有使用过这个API,但是看网上的例子,在这个指针中传递self似乎很正常。然后,如果uploadQueue 是一个实例变量,您可以通过属性使其可访问(并具有访问类实例中所有内容的额外优势)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-29
      • 1970-01-01
      • 2014-03-26
      • 1970-01-01
      • 1970-01-01
      • 2016-12-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多