ios在后台线程上写入磁盘

wjh*_*wjh 12 multithreading ios

我目前正在通过调用在后台线程中将一些文件写入磁盘

dispatch_async(my_queue,^{
   [self writeToRoot:filename data:data];
};

- (BOOL)writeToRoot:(NSString *)path data:(NSData *)content
{
    NSString *fullPath = [[self rootPath] stringByAppendingPathComponent:path];

    NSString *pathWithoutFile = [fullPath stringByDeletingLastPathComponent];

    BOOL directoryExists = [[NSFileManager defaultManager] fileExistsAtPath:pathWithoutFile];

    if (!directoryExists) {
        NSError *error = nil;
        [[NSFileManager defaultManager] createDirectoryAtPath:pathWithoutFile
                                  withIntermediateDirectories:YES
                                                   attributes:nil error:&error];
        NSParameterAssert(error == nil);
    }

    return [content writeToFile:fullPath atomically:NO];
}
Run Code Online (Sandbox Code Playgroud)

我这样做,因为它不会阻止主线程.我的问题是如何确保线程安全.在执行此后台操作时,当我尝试通过调用从磁盘读取文件时会发生什么:

[NSData dataWithContentsOfFile:fullPath];
Run Code Online (Sandbox Code Playgroud)

内容会被破坏吗?或者写操作会锁定文件,读操作会等到写完成吗?

Rob*_*Rob 20

我倾向于dispatch_sync你的读操作以my_queue确保线程安全(假设它是一个串行队列).您还可以使用任何各种同步工具(例如锁或@synchronized指令),但鉴于您已经为文件交互设置了队列,使用该串行队列可能是最简单的.

并发编程指南消除锁定代码部分中讨论了使用队列来协调与共享资源的交互的技术.


顺便说一句,如果你保存在后台队列中(这意味着保存操作可能足够慢以证明在后台进行操作),那么确保你请求一点时间来完成操作是明智的.在保存操作正在进行时,应用程序本身被中断(即用户点击物理主页按钮,呼叫进来等).您可以beginBackgroundTaskWithExpirationHandler在调度保存操作之前通过调用完成此操作,并endBackgroundTask在完成后调用:

UIApplication *application = [UIApplication sharedApplication];

// get background task identifier before you dispatch the save operation to the background

UIBackgroundTaskIdentifier __block task = [application beginBackgroundTaskWithExpirationHandler:^{
    if (task != UIBackgroundTaskInvalid) {
        [application endBackgroundTask:task];
        task = UIBackgroundTaskInvalid;
    }
}];

// now dispatch the save operation

dispatch_async(my_queue, ^{

    // do the save operation here

    // now tell the OS that you're done

    if (task != UIBackgroundTaskInvalid) {
        [application endBackgroundTask:task];
        task = UIBackgroundTaskInvalid;
    }
});
Run Code Online (Sandbox Code Playgroud)

即使应用程序被中断,这也将确保您的保存操作有成功完成的机会.

而且,正如Jsdodgers指出的那样,你可能也想要执行原子写操作.