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
相关产品推荐
相关产品推荐

