Search code examples
iosswiftiphoneavfoundation

Saving a video in FileManager doesn't work when the app reopens


I am recording a video in my app and I want to save that video and play it any time I want. Everything works fine but when I reopen the app, the file is no longer available (there's no data in the file URL).

This is how I do it:

I record a video and I wait until the delegate fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) hits. In this function I grab the data from the outputURL and I save it first in the user's gallery and then in the FileManager local directory:

func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
        if error == nil {
            try? PHPhotoLibrary.shared().performChangesAndWait {
                PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: outputFileURL)
            }
            SVProgressHUD.show()

            do {
                if let data = try? Data(contentsOf: outputFileURL) {
                    let localDirectoryURL = self.saveToLocalDirectory(nameWithExtension: "\(randomString(length: 10)).mp4", data: data)
                    viewModel.outputVideoURL = localDirectoryURL ?? outputFileURL
                    viewModel.createAndSaveLocalVideo(url: localDirectoryURL ?? outputFileURL)
                } else {
                    SVProgressHUD.showError(withStatus: "Something wrong happened")
                }
                
            }
}
func saveToLocalDirectory(nameWithExtension: String, data: Data) -> URL? {
        guard let documentDirectoryPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
            return nil
        }
        
        let path = documentDirectoryPath.appendingPathComponent(nameWithExtension)
        do {
            try data.write(to: path)
            return path
        } catch {
            print(error.localizedDescription)
            return nil
        }
    }

I save the file URL in UserDefaults and I play try to play it. If I haven't closed the app yet, everything works as expected. But when I close the app and relaunch it I get: Error Domain=NSCocoaErrorDomain Code=260 "The file “33eLKbc8kA.mp4” couldn’t be opened because there is no such file."

There's no errors thrown at any point and as I mentioned, it works perfect when I try to reproduce it through that URL in the same app session.

Right now I'm recording 10-15 seconds video but I will be recording up to 60 to 75 minutes. It's not in 4K and it weights around 500mb when its a 60 min video.

What am I doing wrong?


Solution

  • By design the path to documents directory will change every time you reopen your application. So instead of saving a full URL you should only save the last part of your URL (file name most likely).

    So simply save your nameWithExtension and then recreate full path by having something like

    func urlForVideo(nameWithExtension: String) -> URL? {
        return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent(nameWithExtension)
    }
    

    and use this code both when loading and saving your file.