gpt4 book ai didi

ios - performBlock : and performBlockAndWait:? 之间的行为差​​异

转载 作者:行者123 更新时间:2023-12-02 03:39:45 27 4
gpt4 key购买 nike

我正在创建一个 NSManagedObjectContext在私有(private)队列中处理我从文件和/或服务中获取的数据更新:

NSManagedObjectContext *privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
privateContext.persistentStoreCoordinator = appDelegate.persistentStoreCoordinator;

由于我使用的是私有(private)队列,所以我不完全理解 performBlock: 之间的区别和 performBlockAndWait:方法...要执行我的数据更新,我目前正在这样做:
[privateContext performBlock: ^{

// Parse files and/or call services and parse
// their responses

// Save context
[privateContext save:nil];

dispatch_async(dispatch_get_main_queue(), ^{
// Notify update to user
});
}];

在这种情况下,我的数据更新是同步和顺序进行的,所以我认为这是保存上下文的正确位置,对吗?如果我做错了什么,如果你让我知道,我将不胜感激。另一方面,这段代码是否等效?:
[privateContext performBlockAndWait: ^{

// Parse files and/or call services and parse
// their responses

// Save context
[privateContext save:nil];
}];

// Notify update to user

我再次想这是保存上下文的正确位置......这两种方法之间有什么区别(如果有的话,在这种情况下)?

如果不是执行同步服务调用或文件解析,我需要执行异步服务调用怎么办?如何管理这些数据更新?

提前致谢

最佳答案

你是对的,你想用 MOC 做的任何事情都必须在 performBlock 内完成。或 performBlockAndWait .请注意,保留/释放对于托管对象是线程安全的,因此您不必在这些块之一内保留/释放托管对象上的引用计数。

它们都利用同步队列来处理消息,这意味着一次只能执行一个块。嗯,这几乎是真的。见performBlockAndWait的说明.在任何情况下,对 MOC 的访问都将被串行化,以便一次只有一个线程正在访问 MOC。

tl;dr 不要担心差异,始终使用 performBlock .

事实差异

有许多不同之处。我相信还有更多,但这里是我认为最重要的理解。

同步与异步
performBlock是异步的,因为它立即返回,并且该块在 future 某个时间在某个未公开的线程上执行。通过 performBlock 提供给 MOC 的所有区块将按照添加的顺序执行。
performBlockAndWait是同步的,因为调用线程将等到块执行完毕后再返回。块是在其他线程中运行,还是在调用线程中运行并不是那么重要,并且是一个无法信任的实现细节。

但是请注意,它可以实现为“嘿,某个其他线程,去运行这个块。我会坐在这里什么都不做,直到你告诉我它完成了。”或者,它可以实现为“嘿,Core Data,给我一个锁,防止所有其他块运行,这样我就可以在我自己的线程上运行这个块。”或者它可以以其他方式实现。再次,实现细节,它可以随时更改。

不过,我会告诉你这一点,我上次测试它时,performBlockAndWait在调用线程上执行块(意思是上一段中的第二个选项)。这只是帮助您了解正在发生的事情的真正信息,不应以任何方式依赖。

重入性
performBlock总是 异步,因此不可重入。好吧,有些人可能会认为它是可重入的,因为您可以从使用 performBlock 调用的块中调用它。 .但是,如果您这样做,所有调用 performBlock将立即返回,并且该块至少在 之前不会执行当前 执行块完全完成它的工作。

[moc performBlock:^{
doSomething();
[moc performBlock:^{
doSomethingElse();
}];
doSomeMore();
}];

这些函数将始终按以下顺序执行:
doSomething()
doSomeMore()
doSomethingElse()
performBlockAndWait总是 同步。此外,它也是可重入的。多次调用不会死锁。因此,如果您最终拨打 performBlockAndWait当你在一个由于另一个 performBlockAndWait 而运行的块中时,然后就OK了。您将获得预期的行为,因为第二次调用(以及任何后续调用)不会导致死锁。此外,正如您所期望的那样,第二个将在返回之前完全执行。
[moc performBlockAndWait:^{
doSomething();
[moc performBlockAndWait:^{
doSomethingElse();
}];
doSomeMore();
}];

这些函数将始终按以下顺序执行:
doSomething()
doSomethingElse()
doSomeMore()

先进先出

FIFO 代表“先进先出”,这意味着块将按照它们放入内部队列的顺序执行。
performBlock始终遵循内部队列的 FIFO 结构。每个块都会被插入到队列中,并且只有在它被移除时才会运行,按照 FIFO 的顺序。

根据定义, performBlockAndWait打破 FIFO 排序,因为它跳过已经入队的块队列。

使用 performBlockAndWait 提交的块不必等待队列中正在运行的其他块。有很多方法可以看到这一点。一个简单的就是这个。
[moc performBlock:^{
doSomething();
[moc performBlock:^{
doSomethingElse();
}];
doSomeMore();
[moc performBlockAndWait:^{
doSomethingAfterDoSomethingElse();
}];
doTheLastThing();
}];

这些函数将始终按以下顺序执行:
doSomething()
doSomeMore()
doSomethingAfterDoSomethingElse()
doTheLastThing()
doSomethingElse()

在这个例子中很明显,这就是我使用它的原因。但是,请考虑一下,如果您的 MOC 正在从多个地方调用它。可能有点困惑。

不过要记住的是, performBlockAndWait是抢占式的,可以跳过FIFO队列。

僵局

您永远不会遇到死锁调用 performBlock .如果你在块内做了一些愚蠢的事情,那么你可能会死锁,但调用 performBlock永远不会陷入僵局。您可以从任何地方调用它,它只会将块添加到队列中,并在将来的某个时间执行它。

您可以通过拨打 performBlockAndWait 轻松获得死锁。 ,特别是如果您从外部实体可以调用的方法中调用它,或者在嵌套上下文中不加选择地调用它。具体来说,如果父级调用 performBlockAndWait,您几乎肯定会死锁您的应用程序。在一个 child 身上。

用户事件

Core Data 认为“用户事件”是调用 processPendingChanges 之间的任何事件。 .您可以阅读有关此方法为何重要的详细信息,但“用户事件”中发生的事情对通知、撤消管理、删除传播、更改合并等有影响。
performBlock封装了一个“用户事件”,这意味着代码块在对 processPendingChanges 的不同调用之间自动执行。 .
performBlockAndWait不封装“用户事件”。如果您希望将块视为不同的用户事件,则必须自己进行。

自动释放池
performBlock将块包装在它自己的自动释放池中。
performBlockAdWait不提供唯一的自动释放池。如果你需要一个,你必须自己提供。

个人意见

就我个人而言,我认为使用 performBlockAndWait 的理由并不多。 .我敢肯定有人有一个无法以任何其他方式完成的用例,但我还没有看到它。如果有人知道该用例,请与我分享。

最近的电话是 performBlockAndWait在父上下文中(永远不要在 NSMainConcurrencyType MOC 上这样做,因为它可能会锁定您的 UI)。例如,如果要确保在当前块返回并且其他块有机会运行之前数据库已完全保存到磁盘。

因此,不久前,我决定将 Core Data 视为一个完全异步的 API。结果,我有一大堆核心数据代码,而且我没有一次调用 performBlockAndWait ,测试之外。

这样的生活要好得多。当我认为“它一定有用,否则他们不会提供它”时,我遇到的问题要少得多。

现在,我根本不再需要 performBlockAndWait .结果,也许它已经改变了一些,我只是错过了它,因为它不再让我感兴趣……但我对此表示怀疑。

关于ios - performBlock : and performBlockAndWait:? 之间的行为差​​异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32198678/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com