我想在不同的队列中执行一些操作,所以我使用semaphore.But --当我用仪器检查它时,会出现泄漏。这个框架是dispatch_semaphore_create。我用ARC当我检查它的时候没有泄漏。代码看起来像:
dispatch_async(queue,^{
dispatch_semaphore_t signal = dispatch_semaphore_create(1);
for (int i=0;i<100;i++)
{
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
dispatch_async(queue,^{
/* some actions */
dispatch_semaphore_signal(signal);
});
}
});代码是这样的,我输入时使用WINDOWS计算机,所以有一些拼写错误,对不起。
附注:
我希望用动画逐个删除表视图中的单元格,如果我使用deleteRowsAtIndexpaths方法删除它们的索引路径数组,或者在主队列中循环删除它们,则它们将一起删除,而不是一个接一个地删除,所以我使用两个队列进行删除。守则是这样的:
dispatch_async(queue,^{
dispatch_semaphore_t signal = dispatch_semaphore_create(1);
for (int i=0;;i++)
{
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
if (i == [indexPathsAry count])
{
dispatch_semaphore_signal(finishAllSignal);
break;
}
dispatch_async(main_queue,^{
NSIndexPath *indexPath = indexPathsAry[0];
id item = items[indexPath.row];
[items removeObject:item];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:indexPath withAnimation:...];
[tableView endUpdates];
dispatch_semaphore_signal(signal);
});
}
});对不起,NSIndexPath *indexPath = indexPathsAryi;需要更改为NSIndexPath *indexPath = indexPathsAry;代码将逐个正确地删除单元格,而不是一起删除它们。它说在行dispatch_semaphore_t signal =dispatch_semaphore_create(1)中有漏洞;但是当我在一个小演示中测试这段代码时,它工作得很好,所以我不知道为什么。一开始我使用dispatch_sync而不是信号量,但它有时不能同步工作,这让我感到困惑。是因为我的项目中队列太多了吗?
发布于 2013-11-23 13:45:16
从您发布的代码来看,您泄漏的原因并不明显。也就是说,使用后台队列和信号量可能不是最好的方法。充其量,它会留下两个线程在序列的大部分时间内被阻塞(一个会周期性地唤醒以对下一个删除操作进行队列,另一个正在等待finishAllSignal)。有更好的方法。哪种方法是最好的,真正取决于你想要的确切效果。
例如,在常见的情况下,您的当前方法似乎允许(至少)在启动delete操作/动画之间允许(至少)一个主运行循环(请参见下面的解释)。我的第一个想法是使用一个计时器开始每删除一个或两个比前一个帧。看起来会是这样的:
NSArray* indexPathsAry = @[ ... ];
const NSTimeInterval intervalInSeconds = 1.0 / 30.0;
__block NSUInteger i = 0;
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, (uint64_t)(intervalInSeconds * NSEC_PER_SEC), 0);
dispatch_source_set_event_handler(timer, ^{
NSIndexPath *indexPath = indexPathsAry[i++];
id item = items[indexPath.row];
[items removeObject:item];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:indexPath withAnimation:...];
[tableView endUpdates];
if (i >= indexPathsAry.count)
{
dispatch_source_cancel(timer);
}
});
dispatch_source_set_cancel_handler(timer, ^{
// whatever you want to happen when all the removes are done.
})
dispatch_resume(timer);如果您确实需要保证运行循环的确切/只有一个自旋(信号量方法FWIW不能保证这一点),那么NSOperation可能是最简单的方法(因为主线程NSOperationQueue每个运行循环只提供一个操作)。如果您需要“完成”行为(即finishAllSignal),您可以使用NSOperation依赖关系来实现这一点。看起来可能是这样的:
NSOperation* finishOp = [NSBlockOperation blockOperationWithBlock:^{
// ... whatever you want to have happen when all deletes have been processed.
}];
for (NSIndexPath* toDelete in indexPathsAry)
{
NSOperation* op = [NSBlockOperation blockOperationWithBlock:^{
id item = items[toDelete.row];
[items removeObject: item];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths: @[toDelete] withAnimation:...];
[tableView endUpdates];
}];
[finishOp addDependency: op];
[[NSOperationQueue mainQueue] addOperation: op];
}
[[NSOperationQueue mainQueue] addOperation: finishOp];这两种方法都不应该有漏洞。此外,这两种方法中的任何一种都比让两个线程在信号量上等待时间更长。
更多详细信息:
下面是我认为发布的方法将做什么的解释:
需要注意的一点是,主运行循环和后台线程之间没有强耦合。如果在您的块之后的主队列上有另一个不相关的块,那么后台队列可能会在不相关的块完成之前将下一个delete块放到主队列上。如果发生这种情况,这两个delete块可以在相同的runloop pass上执行,并且两个相应的项似乎同时被删除。在一般情况下,这种情况可能不会发生,但我的观点是,信号量方法不能保证单删除每运行循环的行为,但我相信NSOperation方法将保证这样做。
老实说,计时器方法可能是最好的,因为它在语义上捕捉到了您在这里想要的内容,即行之间有一些最小的延迟就可以一个接一个地删除。
发布于 2013-11-23 13:59:47
我看不出这是怎么回事,因为我觉得这段代码有很多问题:
deleteRowsAtIndexPaths只启动动画。这段代码将使它们看起来几乎同时被删除。i == 0删除第一项时,一切都很好,但是到了i == 1时,数组中的第二项现在是数组中的第一项,所以当您引用indexPathsAry[i]时,您现在正在抓取原来的第三项,就像原来的第二项现在在indexPathsAry[0]上一样。deleteRowsAtIndexPaths方法接受一个索引路径数组,而不是一个索引路径。尽管如此,在这个代码示例中,我没有看到任何可能导致泄漏的东西(这是您最初的问题)。您应该共享哪些对象被报告为泄漏的信息。
顺便说一句,如果您想在从表中删除所有内容之前将可见单元格从表中移除,您还可以这样做:
NSInteger count = [self.tableView.indexPathsForVisibleRows count];
// first animate the cells flying off to the right
[self.tableView.indexPathsForVisibleRows enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
[UIView animateWithDuration:0.25 delay:idx * 0.05 options:0 animations:^{
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.transform = CGAffineTransformMakeTranslation(self.view.frame.size.width, 0);
} completion:^(BOOL finished) {
// if it's the last one, empty the data source and refresh the table
if (idx == (count - 1)) {
[self emptyTableDataSource];
[self.tableView reloadData];
}
}];
}];https://stackoverflow.com/questions/20149063
复制相似问题