when trying to use .duration to get the length of the video i get the warning "'duration' was deprecated in iOS 16.0: Use load(.duration) instead", but when i try to use load(.duration) i get the errorr " Type of expression is ambiguous without more context" on line FileStorage.uploadVideo(videoData, directory: fileDirectory).
using 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) 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)
}
using 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()is an async method. I'm not certain where you're getting the closure syntax here. You need to move this work to an async context, and await the result:I've moved the Task to the MainActor, since you perform UIKit-related operation in the block. (This may be implicit in a UIViewController, so I'm not 100% certain that
@MainActor inis required in your situation.)Note that you're doing a lot of possibly expensive I/O operations on the main queue here. For example,
NSData(contentsOf:options:)is not appropriate for loading large files on the main queue (it's barely appropriate for reading small files). This can cause hangs on the UI thread, and even terminate the app if it takes too long (requesting memory mapping does not promise this won't happen). Most of this code should probably be built around AVAsset and its related Reader and Writer directly, rather than trying to manage things by hand with NSData.