You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHPickerViewController上传视频至Firebase遇NSItemProviderErrorDomain-1000错误

视频上传错误排查与修复

我使用PHPickerViewController从相机胶卷选择视频上传至Firebase,短视频有时能成功但上传速度慢,长视频则频繁出现以下错误:

Error Domain=NSItemProviderErrorDomain Code=-1000 "Cannot load representation of type com.apple.quicktime-movie" UserInfo={NSLocalizedDescription=Cannot load representation of type com.apple.quicktime-movie}

现有实现代码
func uploadVideo(videoURL: URL)
{
    let storage = Storage.storage()
    let storageRef = storage.reference()
    
    let videoRef = storageRef.child("rPosts/\(uid!)/\(fileID).mov")
    let metadata = StorageMetadata()
    metadata.contentType = "video/quicktime"
    
    var videoData: Data = Data()
    
    do
    {
        videoData = try Data(contentsOf: videoURL)
    }
    catch
    {
        print(error.localizedDescription)
        return
    }
    
    videoRef.putData(videoData, metadata: metadata)
    { (metaData, error) in
        guard error == nil else
        {
            self.errorLabel.text = error!.localizedDescription
            return
        }
        
        print("greenchecktimeebabyyyy AHHHH")
    }
}

extension postingRViewController: PHPickerViewControllerDelegate
{
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            picker.dismiss(animated: true, completion: nil)

            for result in results {
                
                print("made result")
                var went = false
                
                result.itemProvider.loadFileRepresentation(forTypeIdentifier: "com.apple.quicktime-movie")
                { videoURL, error in
                    result.itemProvider.loadFileRepresentation(forTypeIdentifier: "com.apple.quicktime-movie") { videoURL, error in
                        
                        assert(Thread.isMainThread == false)

                        let directory = NSTemporaryDirectory()
                        let fileName = NSUUID().uuidString.appending(".mov")
                        
                        print("loading")
                        went = true

                        if let videoURL = videoURL,
                           let copiedURLFile = NSURL.fileURL(withPathComponents: [directory, fileName]) {
                            try! FileManager.default.copyItem(at: videoURL, to: copiedURLFile)
                            DispatchQueue.main.async {
                                // the videourl is deleted. Only copiedURLFile exists
                                // upload_to_firebase(video url)
                                self.uploadVideo(videoURL: copiedURLFile)
                                print("uploaded to the cloud")

                                // after the video is presented or the file uploaded, delete copiedURLFile
                            }
                        }
                        else { print(error!) }
                }
            }
        }
问题分析与修复方案
  • 重复调用资源加载方法:代码中连续两次调用loadFileRepresentation,同一视频资源被重复触发加载,长视频加载耗时久,容易引发资源冲突导致加载失败,直接移除重复调用即可。
  • 内存加载完整视频:用Data(contentsOf:)将长视频全部读入内存,会瞬间占用大量内存,不仅拖慢上传速度,还可能触发系统内存警告,导致加载或上传失败。改用Firebase Storage的putFile方法直接上传文件URL,无需将整个文件加载到内存。
  • 强制解包风险:try!会在文件拷贝失败时直接崩溃,替换为do-catch处理异常,避免崩溃同时捕获错误信息。
  • 临时文件未清理:上传完成后需删除临时拷贝的文件,避免持续占用设备存储空间。
  • 错误处理不完整:补充loadFileRepresentation的错误处理逻辑,及时向用户反馈加载失败信息。
修复后的代码
func uploadVideo(videoURL: URL, completion: @escaping (Error?) -> Void) {
    let storage = Storage.storage()
    let storageRef = storage.reference()
    let videoRef = storageRef.child("rPosts/\(uid!)/\(fileID).mov")
    let metadata = StorageMetadata()
    metadata.contentType = "video/quicktime"
    
    // 直接上传文件URL,无需加载整个视频到内存
    videoRef.putFile(from: videoURL, metadata: metadata) { metaData, error in
        if let error = error {
            self.errorLabel.text = error.localizedDescription
            completion(error)
            return
        }
        print("上传成功")
        completion(nil)
    }
}

extension postingRViewController: PHPickerViewControllerDelegate {
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        picker.dismiss(animated: true, completion: nil)
        
        for result in results {
            result.itemProvider.loadFileRepresentation(forTypeIdentifier: "com.apple.quicktime-movie") { [weak self] videoURL, error in
                guard let self = self else { return }
                
                if let error = error {
                    print("加载视频失败:\(error.localizedDescription)")
                    DispatchQueue.main.async {
                        self.errorLabel.text = "视频加载失败,请重试"
                    }
                    return
                }
                
                guard let videoURL = videoURL else {
                    DispatchQueue.main.async {
                        self.errorLabel.text = "无法获取视频文件"
                    }
                    return
                }
                
                // 拷贝到临时目录(原文件会被系统自动清理,拷贝后可稳定保留至上传完成)
                let directory = NSTemporaryDirectory()
                let fileName = NSUUID().uuidString.appending(".mov")
                guard let copiedURL = NSURL.fileURL(withPathComponents: [directory, fileName]) else {
                    DispatchQueue.main.async {
                        self.errorLabel.text = "创建临时文件失败"
                    }
                    return
                }
                
                do {
                    try FileManager.default.copyItem(at: videoURL, to: copiedURL)
                    DispatchQueue.main.async {
                        // 上传临时文件,完成后删除
                        self.uploadVideo(videoURL: copiedURL) { error in
                            // 无论上传成功或失败,都清理临时文件
                            try? FileManager.default.removeItem(at: copiedURL)
                        }
                    }
                } catch {
                    print("拷贝文件失败:\(error.localizedDescription)")
                    DispatchQueue.main.async {
                        self.errorLabel.text = "视频拷贝失败,请重试"
                    }
                }
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者EAO123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 00:39:17