Is it possible to use NSFileManager's `copyIte

2019-08-26 13:17发布

问题:

I'm working on an iOS app, uploading videos from the Camera Roll, using NSURLSession with a background configuration. The user can queue up multiple videos for upload (the queue is executed serially).

A single upload consists of:

  1. Getting an AVURLAsset reference to the PHAsset using PHImageManager's requestAVAssetForVideo method.
  2. Copying the resource to a temp directory (because you cannot upload straight from the AVURLAsset's URL).
  3. Uploading the resource using an NSURLSessionUploadTask

I can queue up multiple videos and the process works well in the foreground. They complete one after another.

But if I queue up several videos and then background the app. As soon as execution reaches the copyItemAtURL:toURL:error: stage it stalls until I foreground the app again. (I know this because I'm posting debug statements in local notifications, visible on the lock screen).

Is it possible to use copyItemAtURL:toURL:error: when the app is backgrounded?

If not, is it possible to use an AVAssetExportSession instead?

Edit 1 I've tested this while connected to the debugger and while not, the app never executes the copy command. But does so only when the app is foregrounded again.

Edit 2 To clarify, execution stalls at the copy command. It doesn't yield an error and continue execution. And implementing the fileManager:shouldCopyItemAtURL:toURL: delegate method doesn't change things. The docs for that method also say:

Prior to copying each item, the file manager asks its delegate if it should actually do so. It does this by calling the fileManager:shouldCopyItemAtURL:toURL: method; if that method is not implemented (or the process is running in OS X 10.5 or earlier) it calls the fileManager:shouldCopyItemAtPath:toPath: method instead. If the delegate method returns YES, or if the delegate does not implement the appropriate methods, the file manager proceeds to copy the file or directory.

回答1:

What kind of URL are you getting for the AVURLAsset? There are two, and the distinction is always relevant (take the URL generated by UIImagePickerController versus the one used by AVAssetReader/Writer:

I can demonstrate with this:

[[PHImageManager defaultManager] requestAVAssetForVideo:phAsset options:nil resultHandler:^(AVAsset *avAsset, AVAudioMix *audioMix, NSDictionary *info) {
    NSURL *url = (NSURL *)[[(AVURLAsset *)avAsset URL] fileReferenceURL];
    NSLog(@"url = %@", [url absoluteString]);
    NSLog(@"url = %@", [url relativePath]);
 }];

Whereas phAsset is the PHAsset object, and avAsset is the resulting AVAsset object generated by PHImageManager, the output to the console from the above code will produce, for example:

2016-04-16 01:15:40.155 ChromaEpsilon[3423:933358] url = file:///.file/id=16777218.8262005
2016-04-16 01:15:40.155 ChromaEpsilon[3423:933358] url = /private/var/mobile/Media/DCIM/108APPLE/IMG_8421.MOV

There's more than just these two, I believe, but start here.