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

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))
    }
}

关键修正点

  1. 消除闭包歧义:移除uploadVideo闭包中videoURL: String?的显式类型标注,Swift会根据方法定义自动推断参数类型,解决上下文歧义问题。
  2. 类型安全优化:load(.duration)的success回调中,duration原生类型就是CMTime,无需强制转换,避免运行时崩溃风险。
  3. 代码健壮性提升:用guard语句替代强制解包,减少潜在崩溃点;异步回调中可根据需求添加[weak self]捕获列表,避免循环引用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 23:50:01