Я работаю с AWS S3 в приложении iOS, используя Swift 6. У меня есть односложный класс AWSS3Manager , который обрабатывает загрузку и удаление изображений, видео и других файлов. Однако после перехода на Swift 6 я испытываю частые сбои при загрузке или удалении нескольких изображений или отдельного изображения. Проблема, по-видимому, связана с тем, что блоки завершения называются ненадлежащим образом или несколько раз, особенно во время загрузки изображения или при перегрузке через uploadimages .
Добавление nonIsolated в uploadImage & uploadfile и сделав их асинхрономатическим/ожиданием и удалением @mainactor решило проблему. Так что теперь нет сбоя, но я не могу сказать, что это лучшее решение или нет?
Я работаю с AWS S3 в приложении iOS, используя Swift 6. У меня есть односложный класс AWSS3Manager , который обрабатывает загрузку и удаление изображений, видео и других файлов. Однако после перехода на Swift 6 я испытываю частые сбои при загрузке или удалении нескольких изображений или отдельного изображения. Проблема, по-видимому, связана с тем, что блоки завершения называются ненадлежащим образом или несколько раз, особенно во время загрузки изображения или при перегрузке через uploadimages . [code]@MainActor class AWSS3Manager{
static let shared = AWSS3Manager() // 4 private init () { initializeS3() } let bucketName = "Bucket_Name" //5
func initializeS3() { if S3Key == "" || S3SecretKeyName == "" { // if let topVC = UIApplication.topViewController() { // topVC.showError("Something went wrong!") // } debugPrint("AWS initialisation Error") return } let credentials = AWSStaticCredentialsProvider(accessKey: S3Key, secretKey: S3SecretKeyName) let configuration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: credentials)
if images.count == 0 || InternetConnectionManager.isConnectedToNetwork() == false { completion(nil, nil) } if AWSServiceManager.default().defaultServiceConfiguration == nil { initializeS3() let error = NSError(domain: "AWS", code: 1001, userInfo: [NSLocalizedDescriptionKey: "AWS is not initialized."]) completion(nil, error) return } var counter: Int = 0 images.enumerated().forEach { i,image in let imageName: String = String(paths[i].split(separator: "/").last ?? "\(UUID().uuidString).jpeg") if let imageData = image.jpegData(compressionQuality: 0.3), let localUrl = try? saveDataToTempFolder(data: imageData, fileName: imageName){ self.uploadfile(fileUrl: localUrl, fileName: paths[i], contenType: "image", progress: nil) { response, error in counter += 1 if counter == paths.count { completion(nil, error) } } }else{ counter += 1 if counter == paths.count { completion(nil, nil) } } } }
func deleteImage(path: String){ if AWSServiceManager.default().defaultServiceConfiguration == nil { initializeS3() if let topVC = UIApplication.topViewController() { topVC.showError("Something went wrong!") } return } let s3 = AWSS3.default() guard let deleteObjectRequest = AWSS3DeleteObjectRequest() else { return } deleteObjectRequest.bucket = S3BucketName deleteObjectRequest.key = path s3.deleteObject(deleteObjectRequest).continueWith { (task:AWSTask) -> AnyObject? in if let error = task.error { debugPrint("Error occurred: \(error)") return nil } debugPrint("Deleted successfully.") return nil } }
func deleteAllImagesForUser(userID: String) { if AWSServiceManager.default().defaultServiceConfiguration == nil { initializeS3() if let topVC = UIApplication.topViewController() { topVC.showError("Something went wrong!") } return } let s3 = AWSS3.default() let folderPath = "Receipts/\(userID)/"
let listObjectsRequest = AWSS3ListObjectsRequest() listObjectsRequest?.bucket = S3BucketName listObjectsRequest?.prefix = folderPath
s3.listObjects(listObjectsRequest!).continueWith { (task) -> AnyObject? in if let error = task.error { debugPrint("Error occurred while listing objects: \(error)") return nil }
if let listObjectsOutput = task.result, let contents = listObjectsOutput.contents { for object in contents { let deleteObjectRequest = AWSS3DeleteObjectRequest() deleteObjectRequest?.bucket = S3BucketName deleteObjectRequest?.key = object.key
s3.deleteObject(deleteObjectRequest!).continueWith { (deleteTask) -> AnyObject? in if let error = deleteTask.error { debugPrint("Error occurred while deleting object \(object.key ?? ""): \(error)") } else { debugPrint("Deleted \(object.key ?? "") successfully.") } return nil } } } else { debugPrint("No objects found in folder \(folderPath)") } return nil } }
// Upload video from local path url func uploadVideo(videoUrl: URL, progress: progressBlock?, completion: completionBlock?) { let fileName = self.getUniqueFileName(fileUrl: videoUrl) self.uploadfile(fileUrl: videoUrl, fileName: fileName, contenType: "video", progress: progress, completion: completion) }
// Upload files like Text, Zip, etc from local path url func uploadOtherFile(fileUrl: URL, conentType: String, progress: progressBlock?, completion: completionBlock?) { let fileName = self.getUniqueFileName(fileUrl: fileUrl) self.uploadfile(fileUrl: fileUrl, fileName: fileName, contenType: conentType, progress: progress, completion: completion) }
// Get unique file name func getUniqueFileName(fileUrl: URL) -> String { let strExt: String = "." + (URL(fileURLWithPath: fileUrl.absoluteString).pathExtension) return (ProcessInfo.processInfo.globallyUniqueString + (strExt)) }
//MARK:- AWS file upload // fileUrl : file local path url // fileName : name of file, like "myimage.jpeg" "video.mov" // contenType: file MIME type // progress: file upload progress, value from 0 to 1, 1 for 100% complete // completion: completion block when uplaoding is finish, you will get S3 url of upload file here private func uploadfile(fileUrl: URL, fileName: String, contenType: String, progress: progressBlock?, completion: completionBlock?) { if AWSServiceManager.default().defaultServiceConfiguration == nil { initializeS3() if let topVC = UIApplication.topViewController() { topVC.showError("Something went wrong!") } let error = NSError(domain: "AWS", code: 1001, userInfo: [NSLocalizedDescriptionKey: "AWS is not initialized."]) completion?(nil, error) return } // Upload progress block let expression = AWSS3TransferUtilityUploadExpression() expression.progressBlock = {(task, awsProgress) in guard let uploadProgress = progress else { return } DispatchQueue.main.async { uploadProgress(awsProgress.fractionCompleted) } } // Completion block var completionHandler: AWSS3TransferUtilityUploadCompletionHandlerBlock? completionHandler = { (task, error) -> Void in DispatchQueue.main.async(execute: { if error == nil { let url = AWSS3.default().configuration.endpoint.url let publicURL = url?.appendingPathComponent(self.bucketName).appendingPathComponent(fileName) let presignedURL = self.getPreSignedURL(S3DownloadKeyName: fileName) if let completionBlock = completion { completionBlock(fileName, nil) } } else { if let completionBlock = completion { completionBlock(nil, error) } } }) } // Start uploading using AWSS3TransferUtility let awsTransferUtility = AWSS3TransferUtility.default() awsTransferUtility.uploadFile(fileUrl, bucket: bucketName, key: fileName, contentType: contenType, expression: expression, completionHandler: completionHandler).continueWith { (task) -> Any? in if let error = task.error { debugPrint("error is: \(error.localizedDescription)") } if let _ = task.result { // your uploadTask } return nil } } } [/code] [b] reference [/b] https://releases.amplify.aws/aws-sdk-ios/ (spm) 2.40.1 образно (серийный) src="https://i.sstatic.net/yr9NeAb0.png" /> [img]https://i.sstatic.net/ZLT0vI5m.png[/img]
боковая панель
Добавление nonIsolated в uploadImage & uploadfile и сделав их асинхрономатическим/ожиданием и удалением @mainactor решило проблему. Так что теперь нет сбоя, но я не могу сказать, что это лучшее решение или нет?