Swift获取AVAsset视频时长:弃用警告与语法歧义问题
解决AVAsset时长获取的弃用警告与闭包歧义问题
问题分析
- 使用
AVAsset.duration会触发iOS 16.0+的弃用警告,官方推荐改用异步的load(.duration)方法。 - 替换为
load(.duration)后,FileStorage.uploadVideo(videoData, directory: fileDirectory)行出现表达式类型缺乏上下文导致歧义错误,原因是闭包参数的显式类型标注与方法定义的类型推断冲突,同时load方法的异步回调写法也需要调整以保证类型安全。
修正后的完整代码
图片选择器回调处理方法
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { picker.dismiss(animated: true, completion: nil) guard let currentUser = FUser.currentUser() else { return } let message = Message() message.id = UUID().uuidString message.chatRoomId = chatId message.senderId = currentUser.objectId message.senderName = currentUser.username message.sentDate = Date() message.senderInitials = String(currentUser.username.first!) message.status = kSENT message.message = "Video Message" guard let videoUrl = info[.mediaURL] as? URL else { return } let fileName = Date().stringDate() let fileDirectory = "MediaMessages/Video/\(chatId)/_\(fileName).mov" do { let videoData = try NSData(contentsOf: videoUrl, options: .mappedIfSafe) FileStorage.saveVideoLocally(videoData: videoData, fileName: fileName) // 移除闭包参数显式类型标注,消除类型推断歧义 FileStorage.uploadVideo(videoData, directory: fileDirectory) { videoURL in guard let videoURL = videoURL, let url = URL(string: videoURL) else { print("Error: invalid video URL") return } let video = AVURLAsset(url: url) // 类型安全获取视频时长,避免强制转换 video.load(.duration) { result in switch result { case .success(let duration): let durationSeconds = CMTimeGetSeconds(duration) guard durationSeconds <= 30 else { let alert = UIAlertController(title: "Error", message: "The selected video must be less than 30 seconds.", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) self.present(alert, animated: true) return } let outgoingMessage = OutgoingMessage(message: message, videoURL: videoURL, memberId: [FUser.currentId(), self.recipientId]) outgoingMessage.sendMessage(chatRoomId: self.chatId, messageId: message.id, memberIds: [FUser.currentId(), self.recipientId]) PushNotificationService.shared.sendPushNotificationTo(userIds: [self.recipientId], body: message.message) case .failure(let error): print("Failed to load video duration: \(error)") } } } } catch { print("Failed to read video data: \(error)") return } FirebaseListener.shared.updateRecents(chatRoomId: chatId, lastMessage: message.message) }
FileStorage的uploadVideo方法(保持原定义)
class func uploadVideo(_ video: NSData, directory: String, completion: @escaping (_ documentLink: String?) -> Void) { let storageRef = storage.reference(forURL: kFILEREFERENCE).child(directory) var task: StorageUploadTask! task = storageRef.putData(video as Data, metadata: nil) { metaData, error in task.removeAllObservers() ProgressHUD.dismiss() guard error == nil else { print("Error uploading video: \(error!.localizedDescription)") return } storageRef.downloadURL { url, error in guard let downloadUrl = url else { completion(nil) return } print("Video uploaded to: \(downloadUrl.absoluteString)") completion(downloadUrl.absoluteString) } } task.observe(StorageTaskStatus.progress) { snapshot in let progress = Double(snapshot.progress!.completedUnitCount) / Double(snapshot.progress!.totalUnitCount) ProgressHUD.showProgress(CGFloat(progress)) } }
关键修正点
- 消除闭包歧义:移除
uploadVideo闭包中videoURL: String?的显式类型标注,Swift会根据方法定义自动推断参数类型,解决上下文歧义问题。 - 类型安全优化:
load(.duration)的success回调中,duration原生类型就是CMTime,无需强制转换,避免运行时崩溃风险。 - 代码健壮性提升:用
guard语句替代强制解包,减少潜在崩溃点;异步回调中可根据需求添加[weak self]捕获列表,避免循环引用。
内容的提问来源于stack exchange,提问作者fun lab
相关产品推荐
相关产品推荐

