NSFileManager:如何在后台继续向磁盘写入?

4

在我的iPhone应用中,我正在使用默认的NSFileManager来复制和移动一些数据。数据量可能达到几MB,因此可能需要几秒钟才能完成复制。如果用户现在开始复制过程并退出应用程序,我可以在后台模式下继续写入磁盘吗?如果可以,该如何操作?我不想启动一个新的复制进程,而只是完成正在运行的进程。

我目前正在使用两种方法调用:

[imageData writeToFile:path atomically:YES];

并且

[fm copyItemAtPath:sourcePath toPath:destinationPath error:&error];

两个调用都包装在另一个方法中,并通过-performSelectorInBackground:withObject:在后台执行。

另一个问题是我是否可以获得有关写操作进展到哪个阶段的任何信息,或者至少是否已经完成?

编辑:更多信息: 目前,我根本没有实现任何后台任务。当用户按下主页按钮时,正在运行的磁盘操作会发生什么?它们只是被切断了,文件不完整吗?我可以在下一次启动时继续写入吗?它们被取消了,不完整的文件被删除了吗?

总之,我正在将数据写入磁盘,希望在写入操作期间用户按下主页按钮时保持数据一致。我该如何做到这一点?

2个回答

4
您可能需要了解一下NSOperationQueue,文档页面在这里
此外,有两个现有的Stack Overflow问题涉及使用NSOperationQueue,分别是这里这里。两个问题都有被接受的答案。
至于如何确定文件写入是否完成,当我编写一个创建非常大文件的OS X应用程序时,我也遇到了这个问题。我希望用户能够跟踪写入的进度。最终,我使用了一个NSTimer和一个UIProgressBar
基本上,您需要确定文件的(预期)总大小。然后,在写入文件时,您应该有另一个方法(在下面的代码中,我有checkFileWritingProgress),您可以使用NSTimer定期调用它。根据总预期文件大小检查当前进度,并相应地更新UIProgressBar
我提供了一些代码来帮助您入门。
- (void)checkFileWritingProgress:(NSTimer *)someTimer {
    fileAttributes = [fileManager attributesOfItemAtPath:[NSString stringWithFormat:@"%@.data",saveLocation] error:nil];
    currentFileSize = [fileAttributes fileSize]; // instance variable
    if(currentFileSize < maxFileSize) { // maxFileSize is instance variable
        [progressBar setDoubleValue:(((double)currentFileSize/(double)maxFileSize)*100)];
            // progressWindows OS X only... not on iOS
        //[progressWindow setTitle:[NSString stringWithFormat:@"Writing... | %.0f%%",(((double)currentFileSize/(double)maxFileSize)*100)]];
    }
    else {
        [progressBar setDoubleValue:100.0];
    }
}

计时器...

NSTimer *timer = [[NSTimer scheduledTimerWithTimeInterval:0.01
                                                          target:self
                                                        selector:@selector(checkFileWritingProgress:)
                                                        userInfo:nil
                                                         repeats:YES] retain];

//(linked to timer... this is the 
// CORRECT way to use a determinate progress bar)

[progressBar setIndeterminate:NO];
[progressBar setDoubleValue:0.0];
[progressBar displayIfNeeded];

我希望这段代码对您有所帮助。如果有任何需要澄清的地方,请告诉我。


4
默认情况下,当用户按下主页按钮时,您的应用程序并不会真正结束。因此,只要不需要太长时间,它就应该完成该任务。如果需要很长时间,请参考这个问题:如何实现任务完成 有一件事:我认为您对performSelectorInBackground:withObject:的真正作用感到困惑。 “背景”在“……我继续在后台模式下写入磁盘”中使用和“performSelectorIn Background :withObject:”中的“背景”不是同一个背景。
前者的背景: 是指您的应用程序对用户不可见,但仍在运行,至少有一段时间。(当用户按两次主页按钮并切换到另一个应用程序时)
后者的背景: 指的是与主线程相反的后台线程。
在这种情况下,无论您是否使用performSelectorInBackground:withObject:,它都不会影响您的应用程序是否可以在后台模式下运行。这些是完全不同的事情。
您可以在[fm copyItemAtPath:ToPath:error:]之后立即设置BOOL finished = YES,并将其保存在NSUserDefaults中,在您的应用程序再次进入前台时检查该标志;)
希望这可以帮助您;)

背景对我来说是非常清楚的。;) 我只是添加了信息以使其完整。这可能与我后面关于进度的问题有关。设置BOOL并不能真正解决我的问题,因为可能会同时进行多个磁盘操作。 - Björn Marschollek
@Björn 用 int 替代 BOOL 来计算未完成的操作? - David Gelhar
阅读此内容:http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html%23//apple_ref/doc/uid/TP40007072-CH5-SW12 它说系统最多会给你30秒的生命;) 请参见:从这里开始的beginBackgroundTaskWithExpirationHandler:方法:http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html 在过期处理程序中,我会检查:复制了多少百分比?100%80%。 - nacho4d
在30秒内,你可以写入数百兆字节(如果不是更多的话)...那个时间应该足够你使用了 ;) - nacho4d

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接