我正在使用开源软件TMCache。
它节省了昂贵的数据以异步缓存。还有一种同步方法。
它使用dispatch_semaphore_wait()
等待操作结束。
Source
- (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()
处停止工作。这对我来说绝对是不可复制的。上面的方法在
tableView:viewForTableColumn:row:
中调用,因此它在主队列中执行。
知道为什么会这样吗?我必须在另一个队列中使用该方法吗?
最佳答案
您很可能用完了线程。应当释放新的dispatch_semaphore_wait()的dispatch_semaphore_signal(semaphore)需要在新线程中执行(有关详细信息,请参见objectForKey:block:)。如果OS无法调度该新线程,则您将陷入困境,因为没人会向您发送dispatch_semaphore_signal。
发生的频率和时间取决于计算机/设备的速度,滚动表的速度等。这就是为什么您无法在计算机上重现此问题的原因。
此处的快速解决方案是通过使用相同的调度信号量方法(将超时设置为DISPATCH_TIME_NOW)来保持线程数量少,因为您可能不会阻塞主队列。
不过,我希望更改TMCache.m的工作方式。我认为,在这种情况下,调度信号量方法是不合理的-以可靠性为代价来提高代码简洁性(将异步方法包装为同步方法)对我来说似乎不正确。我曾经用异步方法包装同步方法,反之亦然。
这是解决方法
https://github.com/rushproject/TMCache
请注意,仅修补了同步的objectForKey方法。