0

我正在使用开源软件TMCache。它节省了昂贵的数据以异步缓存。还有一种同步方法。

它用于dispatch_semaphore_wait()等待操作结束。


资源

- (id)objectForKey:(NSString *)key
{
    if (!key)
        return nil;

    __block id objectForKey = nil;

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    [self objectForKey:key block:^(TMCache *cache, NSString *key, id object) {
        objectForKey = object;
        dispatch_semaphore_signal(semaphore);
    }];

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    #if !OS_OBJECT_USE_OBJC
    dispatch_release(semaphore);
    #endif

    return objectForKey;
}

这在我的机器上运行良好。在同事的机器上没有。该程序在 停止工作dispatch_semaphore_wait()。这对我来说绝对不可复制。

上面的方法是 in 调用的tableView:viewForTableColumn:row:
所以在主队列中执行。

知道为什么会这样吗?我必须在另一个队列中使用该方法吗?

4

1 回答 1

6

很可能你的线程用完了。应该释放 dispatch_semaphore_wait() 的 dispatch_semaphore_signal(semaphore) 需要在新线程中执行(详见objectForKey:block:)。如果操作系统未能调度该新线程,你就会卡住,因为没有人会向你发送 dispatch_semaphore_signal。

它发生的频率和时间取决于计算机/设备的速度、滚动表格的速度等。这就是为什么您无法在计算机上重现此问题的原因。

这里的快速解决方案是通过使用相同的调度信号量方法将超时设置为 DISPATCH_TIME_NOW 来保持低线程数,因为您可能不会阻塞主队列。

不过,我更愿意改变 TMCache.m 的工作方式。我认为在这种情况下,调度信号量方法是不合理的——以牺牲可靠性为代价获得代码简洁(将异步方法包装到同步对应项中)对我来说似乎不合适。我曾经用异步方法包装同步方法,但反之则不然。

这是修复

https://github.com/rushproject/TMCache

请注意,仅修补了同步 objectForKey 方法。

于 2013-10-11T18:48:07.067 回答