NSFileManager 线程安全
Posted
技术标签:
【中文标题】NSFileManager 线程安全【英文标题】:NSFileManager Thread Safe 【发布时间】:2014-05-18 23:51:22 【问题描述】:根据 Apple 的文档,NSFileManager 在执行基本文件操作时是线程安全的:
"共享的 NSFileManager 对象的方法可以安全地从多个线程调用。但是,如果您使用委托来接收有关移动、复制、删除和链接操作状态的通知,您应该创建一个唯一的实例文件管理器对象,将您的委托分配给该对象,并使用该文件管理器来启动您的操作。”
我一般怎样才能在后台线程上执行我的所有文件操作,同时仍然确保所有文件操作都按照主线程调用它们的顺序执行?
【问题讨论】:
听起来您可能想查看 NSOperationQueue 或 GCD。这里是一些 Apple Docs 的链接:developer.apple.com/library/ios/documentation/General/… 我的 5 分钟结束了,我无法编辑我的评论,但是,我还想说我认为你应该实现一个串行队列。 是的,我知道 GCD,但不确定要搜索什么。我会看看......那么你认为在我的情况下全局串行队列是否有意义? 当然。您说需要在后台线程上按一定顺序执行基本操作,这就是串行队列的用途。我个人喜欢 NSOperationQueue,因为它是一个高级 API,但最终取决于您。如果您确实选择使用 NSOperationQueue,请确保设置 maxConcurrentOperationCount = 1。您还可以为每个操作添加依赖项,例如,操作 B 依赖于操作 A 的完成,使用 addDependency: 方法。 @Max 虽然我更喜欢许多任务(网络队列、图像处理队列等)的操作队列,但对于通过串行队列进行基本同步,我通常建议使用 GCD。它简单高效,非常适合跨线程同步与特定对象的交互。在 并发编程指南 的 Eliminating Lock-Based Code 部分中,他们使用 GCD 对此进行了说明。 【参考方案1】:您可以使用下面的代码来确保文件操作按照您想要的顺序完成。我还编写了一个示例函数,可以从任何线程调用它来执行文件操作。
//this will create a queue
dispatch_queue_t _serialQueue = dispatch_queue_create("com.example.name", DISPATCH_QUEUE_SERIAL);
//call methods on different threads, to be performed one after the other.
dispatch_sync(_serialQueue, ^ printf("1"); //call 1st method here
);
printf("2");
dispatch_sync(_serialQueue, ^ printf("3"); //call second method here
);
printf("4");
执行顺序为1234
下面是一个你可以调用的线程安全的 NSFileManager 方法示例。
-(void)threadSafeMethod //you can call this method from any thread and do file operations
NSFileManager *fileManager = [[NSFileManager alloc] init];
if ([fileManager fileExistsAtPath:sourceFile])
NSError *error = nil;
if (![fileManager copyItemAtPath:sourceFile
toPath:destFile
error:&error])
// Deal with error
如果您查看 NSFileManager 的类文档,概述部分包含以下警告:
共享 FileManager 对象的方法可以从 多个线程安全。但是,如果您使用委托来接收 有关移动、复制、删除和链接状态的通知 操作,您应该创建文件管理器的唯一实例 对象,将您的委托分配给该对象,并使用该文件管理器 开始您的操作。
无论如何,区别仅在于您如何启动 NSFileManager,一个使用 defaultManager,另一个分配 NSFileManager 的瞬间。
希望这会有所帮助。
【讨论】:
以上是关于NSFileManager 线程安全的主要内容,如果未能解决你的问题,请参考以下文章
NSFileManager.contentsOfDirectoryAtURL 返回的文件根据 NSFileManager.fileExistsAtPath 不存在?