iosswiftfile-management

How to get the url for a video saved in temporary directory


I need to save a video file to a temp directory and save the reference to it URL. Currently I have tried using fileManager to create a temp directory and then createFile(atPath: tempDirString, contents: vidData, attributes: nil). But I dont/am not able to save the full reference to the file.

What I have tried:

PHCachingImageManager().requestAVAsset(forVideo: (cell?.assetPH)!, options: nil) { (avAsset, _, _) in
    if let avAsset = avAsset {
        print(avAsset, " the avasset?")
        // vidAVAsset = avAsset

        let avPlayerItem = AVPlayerItem(asset: avAsset)
        let avPlayer = AVPlayer(playerItem: avPlayerItem)
        print(avPlayer, "<-- good?")

        let finalURL = self.urlOfCurrentlyPlayingInPlayer(player: avPlayer)
        print(finalURL, "<-- finalURL YEAH EYAHY YEAH?!?!?")
        // newUserTakenVideo.videoURL = finalURL

        let url = self.addVidToTempURL(vidURL: finalURL!)
        newUserTakenVideo.videoURL = url
        // let newUserTakenVideo = SelectedMedia(videoURL: finalURL, phAsset: (cell?.assetPH)!, thumbnailImg: (cell?.imageView.image)!, uniqueCellID: indexPath)
        // GlobalSharedData.shared.arrayOfCurrentCreateMedia.append(newUserTakenVideo)
    } else {
        print("did noot work")
    }
}

This is the function called:

func addVidToTempURL(vidURL: URL) -> URL? {
    let fileManager = FileManager.default
    let tempDir = fileManager.temporaryDirectory
    let tempDirString = tempDir.path
    do {
        print( "tempDir: \(tempDir)" )
        print( "tempDirString: \(tempDirString)" )
        if fileManager.fileExists(atPath: tempDirString ) {
            print( "tempDir exists" )
            do {
                try fileManager.createDirectory( at: tempDir, withIntermediateDirectories: true, attributes: nil )
                print( "tempDir created" )
                if fileManager.fileExists(atPath: tempDirString ) {
                    print( "tempDir exists" )
                    let vidData = try Data(contentsOf: vidURL)
                    fileManager.createFile(atPath: tempDirString, contents: vidData, attributes: nil)
                    print(tempDirString, " the stringfsdsda")
                    // fileManager.urls(for: fileManager.temporaryDirectory, in: fileManager.)
                    let url = URL(string: tempDirString)
                    return url
                } else {
                    print( "tempDir STILL DOES NOT exist" )
                    return nil
                }
            } catch {
                print( "tempDir NOT created" )
                return nil
            }
        } else {
            print( "tempDir DOES NOT exist" )
            do {
                try fileManager.createDirectory( at: tempDir, withIntermediateDirectories: true, attributes: nil )
                print( "tempDir created" )
                if fileManager.fileExists(atPath: tempDirString ) {
                    print( "tempDir exists" )
                    let vidData = try Data(contentsOf: vidURL)
                    fileManager.createFile(atPath: tempDirString, contents: vidData, attributes: nil)
                    print(tempDirString, " the fsdfdsdfsdfsfsd")
                    let url = URL(string: tempDirString)
                    return url
                } else {
                    print( "tempDir STILL DOES NOT exist" )
                    return nil
                }
            } catch {
                print( "tempDir NOT created" )
                return nil
            }
        }
    }
}

How can I get a URL reference to this files location?

I appreciate any help and can add more information if needed. Thanks, me


Solution

  • Since you don't seem to want your file to be visible to users or persisted between app launches, the Temporary directory sounds perfectly fine for your use case:

    var tempVideoFileUrl: URL {
        return FileManager.default.temporaryDirectory.appendingPathComponent("my_video_name")
    }
    
    func storeVideoToTemporaryFolder(videoData: Data) {
        guard !FileManager.default.fileExists(atPath: tempVideoFileUrl.path) else {
            return
        }
        do {
            try videoData.write(to: tempVideoFileUrl)
        }
        catch {
            fatalError()
        }
    }
    
    func loadVideoFromTemporaryFolder() -> Data? {
        if let data = try? Data(contentsOf: tempVideoFileUrl) {
            return data
        }
        return nil
    }
    

    Worth mentioning though, the system may (and most likely will) purge this directory after the app is exited. It's recommended that you remove any temporary directories/files after they're no longer needed.

    So in your case, you can simply remove it once you finished uploading to Firebase Storage:

    func deleteVideoFromTemporaryFolder() {
        do {
            try FileManager.default.removeItem(at: videoFileUrl)
        }
        catch {
            fatalError()
        }
    }
    

    If you prefer to keep your file around between app launches though, you could use Application Support directory. But since Application Support and Documents directories gets automatically backed up, you may want to exclude your file from iCloud backup by setting its URL's isExcludedFromBackupKey key:

    var applicationSupportVideoFileUrl: URL {
        let applicationSupportFolderUrl = try! FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
        return applicationSupportFolderUrl.appendingPathComponent("my_video_name")
    }
    
    func excludeFromCloudBackup(url: URL) {
        var targetUrl = url
        var isAlreadyExcludedFromBackup: Bool
        do {
            let storedRessourceValues = try targetUrl.resourceValues(forKeys: [URLResourceKey.isExcludedFromBackupKey])
            isAlreadyExcludedFromBackup = storedRessourceValues.isExcludedFromBackup ?? false
        }
        catch {
            fatalError()
        }
        guard !isAlreadyExcludedFromBackup else {
            return
        }
        var ressourceValues = URLResourceValues()
        ressourceValues.isExcludedFromBackup = true
        do {
            try targetUrl.setResourceValues(ressourceValues)
        }
        catch {
            fatalError()
        }
    }
    

    Edit: To get the data from your PHAsset, this should work:

    import Photos
    
    func loadVideoData(phAsset: PHAsset, completion: @escaping (Data?)->()) {
        guard phAsset.mediaType == .video else {
            return completion(nil)
        }
        let options = PHVideoRequestOptions()
        options.isNetworkAccessAllowed = true
        options.deliveryMode = .highQualityFormat
        PHCachingImageManager().requestAVAsset(forVideo: phAsset, options: options) { (avAsset, _, _) in
            guard let avUrlAsset = avAsset as? AVURLAsset else {
                return
            }
            var videoData: Data?
            do {
                videoData = try Data(contentsOf: avUrlAsset.url)
            } catch {
                fatalError()
            }
            DispatchQueue.main.async {
                completion(videoData)
            }
        }
    }
    

    Then simply call this method and store your video in the Temporary folder:

    loadVideoData(phAsset: yourPhAsset) { [weak self] videoData in
        guard let strongSelf = self else { return }
        guard let videoData = videoData else {
            return
        }
        strongSelf.storeVideoToTemporaryFolder(videoData: videoData)
    }