增量读取 UIDocument 时使用哪个线程来执行异步文件访问使用块
Posted
技术标签:
【中文标题】增量读取 UIDocument 时使用哪个线程来执行异步文件访问使用块【英文标题】:Which thread to use for performAsynchronousFileAccessUsingBlock when reading UIDocument incrementally 【发布时间】:2020-07-02 00:59:34 【问题描述】:我逐渐阅读UIDocument
并使用它的performAsynchronousFileAccessUsingBlock
来促进这一点。由于我在主线程上打开文档,因此我注意在主线程上也调用此方法,但这甚至是必要的。
所以我的问题是——我调用哪个线程performAsynchronousFileAccessUsingBlock
有关系吗?
【问题讨论】:
【参考方案1】:是的,你用块调用执行函数的线程很重要。 因为其他线程可能会更改要应用块的文件,最终导致意外/未定义的行为。换句话说,您可以使用其他线程来执行该块,但您必须确保在其他线程完成时有一些东西可以应用,并且可能已经释放了它的内容。
您可以在此处阅读有关 ios 线程安全框架的信息 https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html
还有一个关于使用UIDocument
从源中访问文件的明确讨论,这些文件是您为了您的需要而故意更改的。很简单:它说它必须是线程安全的。
https://developer.apple.com/documentation/uikit/uidocument#1658547
作为
- (void)performAsynchronousFileAccessUsingBlock:(void (^)(void))block API_UNAVAILABLE(tvos);`
有一个 void 返回值并在其自己的后台队列(线程)中运行该块。队列意味着任何调用都将在同一个序列化 blocks 列表中结束。
使用 ^blocks 编码可以让您将源代码保持在一起,以便在队列处理过程中可能的一致工作更容易被关注。 换句话说,您不需要创建额外的线程,也不需要从主线程调用它。文档只说打开、保存、关闭通常是从主线程完成的。
框架为任何 UIDocument 对象提供状态。 “一个 UIDocument 对象在其生命周期的任何时刻都有一个特定的状态”,在这里阅读更多关于它的信息。 https://developer.apple.com/documentation/uikit/uidocument#1658506
希望能为您提供线索以及如何操作。
【讨论】:
谢谢!我同意你的回答,但如果我理解正确,那只是从我的角度来看。因此,您说要小心,因为您的其他线程可能会同时更改块中的文档或内容?这一切都涵盖了,但我要问的是,因为我可以从任何线程调用performAsynchronousFileAccessUsingBlock
并且文档不会警告它,Apple / UIDocument 会在后面正确同步吗?假设我有两个线程同时调用 performAsynchronousFileAccessUsingBlock
会好还是需要同步它们?
指向文档分配内容的指针可以被任何其他线程以任何可能的行为重用,除非您在从不同线程执行异步任务时跟踪所需的查看/解锁状态。这就是该功能为您所做的。在 UIDocument cmets 中,它说:“使用此方法在后台队列上序列化文件访问”,但是在创建您自己的访问设计模式时,有明确的讨论 developer.apple.com/documentation/uikit/uidocument/…【参考方案2】:
不,没关系。
感谢 Ol Sen - 你所说的一切让我觉得答案是 NO 没关系,但我仍然不是 100% 相信,所以让我用下面的代码做一个快速测试。如果没关系,那么这应该运行,如果这样做,应该在某处引发异常。 (这样做是从主线程和后台线程重复调用)。
// Schedule on queue
for ( int i = 0; i < 100; i ++ )
[self.ctl.queue addOperation:[NSBlockOperation blockOperationWithBlock: ^
[self.doc performAsynchronousFileAccessUsingBlock: ^
NSLog(@"Queue %d main %@",i,NSThread.isMainThread ? @"YES" : @"NO" );
];
]];
// Schedule on main
for ( int i = 0; i < 10; i ++ )
[self.doc performAsynchronousFileAccessUsingBlock: ^
NSLog(@"Main %d main %@",i,NSThread.isMainThread ? @"YES" : @"NO" );
];
结果 - 它运行没有任何问题,所以现在我已经说服自己,答案是 不,没关系。显然,您可以从任何线程同时调用它。
这是在主线程上调用的,self.doc
是任意打开的UIDocument
,self.ctl.queue
是后台队列。
我知道文档说通常使用主线程来执行这些操作(打开、保存、关闭),但我曾经因为不遵守这一点而遇到麻烦,所以我一直很小心地发消息UIDocument
仅在主线程上,但对于这个显然过于小心了。
【讨论】:
没错,这就是线程安全框架必须提供的。两个 performAsynchronousFileAccessUsingBlock 调用都将它们的块放在后台的同一个队列中。并且创建线程不必是主线程。 文件访问的一致工作负载更多是设计模式的问题,文件内容的工作在从队列访问时可能不处于假定状态。简而言之:您可以通过在您想要的排序中调用 perform-withBlock 方法来跟踪命令的序列化。 老森!!!再次感谢 - 你知道,我认为我们在所有观点上都同意,但你的语言对我来说有点太强了,所以我很难知道什么时候回答是,什么时候回答不。以上是关于增量读取 UIDocument 时使用哪个线程来执行异步文件访问使用块的主要内容,如果未能解决你的问题,请参考以下文章
使用 setUbiquitous 为 UIDocument 文件关闭 iCloud 同步时出错(LibrarianErrorDomain 错误 2)