当尝试使用 .duration 来获取视频的长度时,我收到警告“'duration' 在 iOS 16.0 中被弃用:改为使用 load(.duration)”,但是当我尝试使用 load(.duration) 时,我得到FileStorage.uploadVideo(videoData, directory: fileDirectory) 上的错误“没有更多上下文的表达式类型不明确”。
使用时长
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
let currentUser = FUser.currentUser()!
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"
if let videoUrl = info[.mediaURL] as? URL {
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
if let videoURL = videoURL, let url = URL(string: videoURL) {
let video = AVURLAsset(url: url)
let duration = video.duration.seconds
if duration > 30 {
let alert = UIAlertController(title: "Error", message: "The selected video must be less than 30 seconds.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
} else {
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)
}
} else {
print("Error: invalid video URL")
return
}
}
} catch {
print(error)
return
}
FirebaseListener.shared.updateRecents(chatRoomId: chatId, lastMessage: message.message)
}
使用 load.duration
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
let currentUser = FUser.currentUser()!
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"
if let videoUrl = info[.mediaURL] as? URL {
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: String?) in
if let videoURL = videoURL, let url = URL(string: videoURL) {
let video = AVURLAsset(url: url)
video.load(.duration) { result in
switch result {
case .success(let durationValue):
let duration = CMTimeGetSeconds(durationValue as! CMTime)
if duration > 30 {
let alert = UIAlertController(title: "Error", message: "The selected video must be less than 30 seconds.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
} else {
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("Error: \(error)")
return
}
}
} else {
print("Error: invalid video URL")
return
}
}
} catch {
` print(error)
return
}
FirebaseListener.shared.updateRecents(chatRoomId: chatId, lastMessage: message.message)
}
}
class func uploadVideo(_ video: NSData, directory: String, completion: @escaping (_ documentLink: String?) -> Void) {
let storageRef = storage.reference(forURL: kFILEREFERENCE).child(directory)
//let imageData = image.jpegData(compressionQuality: 0.6)
var task: StorageUploadTask!
task = storageRef.putData(video as Data, metadata: nil, completion: { (metaData, error) in
task.removeAllObservers()
ProgressHUD.dismiss()
if error != nil {
print("error uploading video", error!.localizedDescription)
return
}
storageRef.downloadURL { (url, error) in
guard let downloadUrl = url else {
completion(nil)
return
}
print("we have uploaded video to ", downloadUrl.absoluteString)
completion(downloadUrl.absoluteString)
}
})
task.observe(StorageTaskStatus.progress) { (snapshot) in
let progress = snapshot.progress!.completedUnitCount / snapshot.progress!.totalUnitCount
ProgressHUD.showProgress(CGFloat(progress))
}
}
.load()
是一种异步方法。我不确定你从哪里得到闭包语法。您需要将此工作移至异步上下文,并等待结果:
if let videoURL = videoURL, let url = URL(string: videoURL) {
let video = AVURLAsset(url: url)
Task { @MainActor in
let duration = try await video.load(.duration).seconds
// ...
}
} else {
// ...
}
我已将任务移至 MainActor,因为您在块中执行与 UIKit 相关的操作。 (这可能隐含在 UIViewController 中,所以我不能 100% 确定您的情况需要
@MainActor in
。)
请注意,您在此处的主队列上执行了很多可能代价高昂的 I/O 操作。例如,
NSData(contentsOf:options:)
不适合在主队列上加载大文件(它几乎不适合读取小文件)。这可能会导致 UI 线程挂起,如果时间过长甚至会终止应用程序(请求内存映射并不能保证不会发生这种情况)。大部分代码应该直接围绕 AVAsset 及其相关的 Reader 和 Writer 构建,而不是尝试使用 NSData 手动管理。