Hello I am saving image to my custom album it saved successfully but random image. I want to save it with custom name. How can I save image with its custom name.
here is code for saving image to custom folder.
func save(image: UIImage, completion: #escaping (Result<Bool, Error>) -> ()) {
self.checkAuthorizationWithHandler { (result) in
switch result {
case .success(let success):
if success, self.assetCollection != nil {
PHPhotoLibrary.shared().performChanges({
let assetChangeRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
let assetPlaceHolder = assetChangeRequest.placeholderForCreatedAsset
if let albumChangeRequest = PHAssetCollectionChangeRequest(for: self.assetCollection) {
let enumeration: NSArray = [assetPlaceHolder!]
albumChangeRequest.addAssets(enumeration)
}
}, completionHandler: { (success, error) in
if let error = error {
print("Error writing to image library: \(error.localizedDescription)")
completion(.failure(error))
return
}
completion(.success(success))
})
}
case .failure(let err):
completion(.failure(err))
}
}
}
Related
I am working on an iOS Swift 5 project and want to download image from my Project App to a folder in gallery. Folder name would be same as my App name and if doesn't exist in gallery, then code should first create App folder in gallery then save image to it.
Need help to resolve this.
as i implemented a year ago
got code from stackoverflow
import Photos
class PhotoManager {
static let instance = PhotoManager()
var folder: PHCollectionList?
/// Fetches an existing folder with the specified identifier or creates one with the specified name
func fetchFolderWithIdentifier(_ identifier: String, name: String) {
let fetchResult = PHCollectionList.fetchCollectionLists(withLocalIdentifiers: [identifier], options: nil)
guard let folder = fetchResult.firstObject else {
createFolderWithName(name)
return
}
self.folder = folder
}
/// Creates a folder with the specified name
private func createFolderWithName(_ name: String) {
var placeholder: PHObjectPlaceholder?
PHPhotoLibrary.shared().performChanges({
let changeRequest = PHCollectionListChangeRequest.creationRequestForCollectionList(withTitle: name)
placeholder = changeRequest.placeholderForCreatedCollectionList
}) { (success, error) in
guard let placeholder = placeholder else { return }
let fetchResult = PHCollectionList.fetchCollectionLists(withLocalIdentifiers: [placeholder.localIdentifier], options: nil)
guard let folder = fetchResult.firstObject else { return }
self.folder = folder
}
}
/// Creates an album with the specified name
private func createAlbumWithName(_ name: String, completion: #escaping (PHAssetCollection?) -> Void) {
guard let folder = folder else {
completion(nil)
return
}
var placeholder: PHObjectPlaceholder?
PHPhotoLibrary.shared().performChanges({
let listRequest = PHCollectionListChangeRequest(for: folder)
let createAlbumRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: name)
listRequest?.addChildCollections([createAlbumRequest.placeholderForCreatedAssetCollection] as NSArray)
placeholder = createAlbumRequest.placeholderForCreatedAssetCollection
}) { (success, error) in
guard let placeholder = placeholder else {
completion(nil)
return
}
let fetchResult = PHAssetCollection.fetchAssetCollections(withLocalIdentifiers: [placeholder.localIdentifier], options: nil)
let album = fetchResult.firstObject
completion(album)
}
}
/// Saves the image to a new album with the specified name
func saveImageToAlbumInRootFolder(_ albumName: String, image: UIImage?, completion: #escaping (Error?) -> Void) {
createAlbumWithName(albumName) { (album) in
guard let album = album else {
return
}
PHPhotoLibrary.shared().performChanges({
let albumChangeRequest = PHAssetCollectionChangeRequest(for: album)
let createAssetRequest = PHAssetChangeRequest.creationRequestForAsset(from: image!)
let photoPlaceholder = createAssetRequest.placeholderForCreatedAsset!
albumChangeRequest?.addAssets([photoPlaceholder] as NSArray)
}, completionHandler: { (success, error) in
if success {
completion(nil)
} else if let error = error {
// Failed with error
} else {
// Failed with no error
}
})
}
}}
currently i am working on a project in office that's why i am not providing you the exact solution but you can figure it out easily from the above class ...
you can use it PhotoManager.instance.saveImageToAlbumInRootFolder(_ albumName: String, image: yourImage) {completion}
import Foundation
import Photos
class CustomPhotoAlbum: NSObject {
static let albumName = "Your App Name"
static let sharedInstance = CustomPhotoAlbum()
var assetCollection: PHAssetCollection!
override init() {
super.init()
if let assetCollection = fetchAssetCollectionForAlbum() {
self.assetCollection = assetCollection
return
}
if PHPhotoLibrary.authorizationStatus() != PHAuthorizationStatus.authorized {
PHPhotoLibrary.requestAuthorization({ (status: PHAuthorizationStatus) -> Void in
()
})
}
if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized {
self.createAlbum()
} else {
PHPhotoLibrary.requestAuthorization(requestAuthorizationHandler)
}
}
func requestAuthorizationHandler(status: PHAuthorizationStatus) {
if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized {
// ideally this ensures the creation of the photo album even if authorization wasn't prompted till after init was done
print("trying again to create the album")
self.createAlbum()
} else {
print("should really prompt the user to let them know it's failed")
}
}
func createAlbum() {
PHPhotoLibrary.shared().performChanges({
PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: CustomPhotoAlbum.albumName) // create an asset collection with the album name
}) { success, error in
if success {
self.assetCollection = self.fetchAssetCollectionForAlbum()
} else {
print("error \(error)")
}
}
}
func fetchAssetCollectionForAlbum() -> PHAssetCollection? {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %#", CustomPhotoAlbum.albumName)
let collection = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)
if let _: AnyObject = collection.firstObject {
return collection.firstObject
}
return nil
}
func save(image: UIImage) {
if assetCollection == nil {
return // if there was an error upstream, skip the save
}
PHPhotoLibrary.shared().performChanges({
let assetChangeRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
let assetPlaceHolder = assetChangeRequest.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(for: self.assetCollection)
let enumeration: NSArray = [assetPlaceHolder!]
albumChangeRequest!.addAssets(enumeration)
}, completionHandler: nil)
}
}
how to use it
func haiJeenyKaMaqsadAuronKKamAna() {
CustomPhotoAlbum.sharedInstance.createAlbum()
CustomPhotoAlbum.sharedInstance.save(image: UIImage(named: "help")!)
}
now this is working fine as i copied it from my old project
This question already has answers here:
Returning data from async call in Swift function
(13 answers)
Closed 3 years ago.
I have a class called CustomPhotoAlbum that has the following function:
func save(image: UIImage) {
self.checkAuthorizationWithHandler { (success) in
if success, self.assetCollection != nil {
PHPhotoLibrary.shared().performChanges({
let assetChangeRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
let assetPlaceHolder = assetChangeRequest.placeholderForCreatedAsset
if let albumChangeRequest = PHAssetCollectionChangeRequest(for: self.assetCollection) {
let enumeration: NSArray = [assetPlaceHolder!]
albumChangeRequest.addAssets(enumeration)
}
}, completionHandler: { (success, error) in
if success {
print("Successfully saved image to Camera Roll.")
}
else {
print("Error writing to image library: \(error!.localizedDescription)")
}
})
}
}
}
Which returns nothing.
I then called the function like this
CustomPhotoAlbum.shared.save(image: finalImage)
My question is, how can i make it return the completionHandler so that i can do something like present an alert from my view controller?
Maybe something like this for me to call
CustomPhotoAlbum.shared.save(image: finalImage) { success in
// do something if successfully saved
}
Just add a completion: (Bool) -> Void parameter and call it whenever appropriate:
func save(image: UIImage, completion: #escaping (Bool) -> Void) {
self.checkAuthorizationWithHandler { (success) in
if success, self.assetCollection != nil {
PHPhotoLibrary.shared().performChanges({
let assetChangeRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
let assetPlaceHolder = assetChangeRequest.placeholderForCreatedAsset
if let albumChangeRequest = PHAssetCollectionChangeRequest(for: self.assetCollection) {
let enumeration: NSArray = [assetPlaceHolder!]
albumChangeRequest.addAssets(enumeration)
}
}, completionHandler: { (success, error) in
if success {
print("Successfully saved image to Camera Roll.")
}
else {
print("Error writing to image library: \(error!.localizedDescription)")
}
completion(success) // here!
})
} else {
completion(false) // and here!
}
}
}
You can add closure as param in save function, like this:
func save(image: UIImage, #escaping completion: ()->Void) {
self.checkAuthorizationWithHandler { (success) in
if success, self.assetCollection != nil {
PHPhotoLibrary.shared().performChanges({
let assetChangeRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
let assetPlaceHolder = assetChangeRequest.placeholderForCreatedAsset
if let albumChangeRequest = PHAssetCollectionChangeRequest(for: self.assetCollection) {
let enumeration: NSArray = [assetPlaceHolder!]
albumChangeRequest.addAssets(enumeration)
}
}, completionHandler: { (success, error) in
if success {
print("Successfully saved image to Camera Roll.")
}
else {
print("Error writing to image library: \(error!.localizedDescription)")
}
})
}
}
}
UIDocumentPickerViewController to pick some document and upload into AWS S3 with help of TransferUtility. Here, While uploading I need to show upload file name, status(progressive loader %),size into tableview cell. If i upload multiple files tableview cell need to show multiple cell with loading status.
Issues:
I have done UIDocumentPickerViewController to pick some documents and get those document URL,name,size,etc. but I don't know how to use (or) pass those values into upload part.
// MARK - File Storage Access
public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
let fileurl: URL = url as URL
let filename = url.lastPathComponent
let fileextension = url.pathExtension
let filedata = url.dataRepresentation
print("DATA: \(filedata)","URL: \(fileurl)", "NAME: \(filename)", "EXTENSION: \(fileextension)")}
//Need to store above values and use it to below functions
Below upload part how to interact with tableview cell.
transferUtility.uploadData(data,bucket: S3BucketName,key: name,contentType: "text/plain",expression: expression,completionHandler: completionHandler).continueWith { (task) -> AnyObject? in
if let error = task.error {
print("Error: \(error.localizedDescription)")
DispatchQueue.main.async {
cells.statusLabel_util.text = "Failed"
print("Failed")
}
}
if let _ = task.result {
DispatchQueue.main.async {
print("Upload Starting!")
}
// Do something with uploadTask.
}
return nil;
}
You can upload file and track progress with this code
if let uploadRequest = AWSS3TransferManagerUploadRequest(){
uploadRequest.bucket = "your bucket"
uploadRequest.key = fileName
//uploadRequest.acl = AWSS3ObjectCannedACL.publicRead
uploadRequest.body = fileUrl
uploadRequest.uploadProgress = {(bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) -> Void in
DispatchQueue.main.async(execute: {() -> Void in
//Update progress
})
}
if let transferManager = AWSS3TransferManager.default(){
transferManager.upload(uploadRequest).continue(with: AWSExecutor.mainThread(), with: { (task) -> Any? in
if let error = task.error as NSError? {
if error.domain == AWSS3TransferManagerErrorDomain, let code = AWSS3TransferManagerErrorType(rawValue: error.code) {
switch code {
case .cancelled, .paused:
break
default:
break
//print("Error uploading: \(uploadRequest?.key) Error: \(error)")
}
} else {
//print("Error uploading: \(uploadRequest?.key) Error: \(error)")
}
return nil
}
return nil
})
}
}
I have a custom album in which my app saves picture from camera. I am wondering if there is a way I can create folders inside my album so I can stack certain images inside it?
ANSWER
As fellow members mentioned, sadly there is no way you can create a folder inside album.
You should try code below. It's Swift 3.0 syntaxe. :)
import Foundation
import Photos
class CustomPhotoAlbum: NSObject {
static let albumName = "Album Name"
static let sharedInstance = CustomPhotoAlbum()
var assetCollection: PHAssetCollection!
override init() {
super.init()
if let assetCollection = fetchAssetCollectionForAlbum() {
self.assetCollection = assetCollection
return
}
if PHPhotoLibrary.authorizationStatus() != PHAuthorizationStatus.authorized {
PHPhotoLibrary.requestAuthorization({ (status: PHAuthorizationStatus) -> Void in
()
})
}
if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized {
self.createAlbum()
} else {
PHPhotoLibrary.requestAuthorization(requestAuthorizationHandler)
}
}
func requestAuthorizationHandler(status: PHAuthorizationStatus) {
if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized {
// ideally this ensures the creation of the photo album even if authorization wasn't prompted till after init was done
print("trying again to create the album")
self.createAlbum()
} else {
print("should really prompt the user to let them know it's failed")
}
}
func createAlbum() {
PHPhotoLibrary.shared().performChanges({
PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: CustomPhotoAlbum.albumName) // create an asset collection with the album name
}) { success, error in
if success {
self.assetCollection = self.fetchAssetCollectionForAlbum()
} else {
print("error \(error)")
}
}
}
func fetchAssetCollectionForAlbum() -> PHAssetCollection? {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %#", CustomPhotoAlbum.albumName)
let collection = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)
if let _: AnyObject = collection.firstObject {
return collection.firstObject
}
return nil
}
func save(image: UIImage) {
if assetCollection == nil {
return // if there was an error upstream, skip the save
}
PHPhotoLibrary.shared().performChanges({
let assetChangeRequest = PHAssetChangeRequest.creationRequestForAsset(from: image)
let assetPlaceHolder = assetChangeRequest.placeholderForCreatedAsset
let albumChangeRequest = PHAssetCollectionChangeRequest(for: self.assetCollection)
let enumeration: NSArray = [assetPlaceHolder!]
albumChangeRequest!.addAssets(enumeration)
}, completionHandler: nil)
}
}
You can add albums within folders in the user's Photos Albums. I just figured out how to do it, today:
import Photos
class PhotoManager {
static let instance = PhotoManager()
var folder: PHCollectionList?
/// Fetches an existing folder with the specified identifier or creates one with the specified name
func fetchFolderWithIdentifier(_ identifier: String, name: String) {
let fetchResult = PHCollectionList.fetchCollectionLists(withLocalIdentifiers: [identifier], options: nil)
guard let folder = fetchResult.firstObject else {
createFolderWithName(name)
return
}
self.folder = folder
}
/// Creates a folder with the specified name
private func createFolderWithName(_ name: String) {
var placeholder: PHObjectPlaceholder?
PHPhotoLibrary.shared().performChanges({
let changeRequest = PHCollectionListChangeRequest.creationRequestForCollectionList(withTitle: name)
placeholder = changeRequest.placeholderForCreatedCollectionList
}) { (success, error) in
guard let placeholder = placeholder else { return }
let fetchResult = PHCollectionList.fetchCollectionLists(withLocalIdentifiers: [placeholder.localIdentifier], options: nil)
guard let folder = fetchResult.firstObject else { return }
self.folder = folder
}
}
/// Creates an album with the specified name
private func createAlbumWithName(_ name: String, completion: #escaping (PHAssetCollection?) -> Void) {
guard let folder = folder else {
completion(nil)
return
}
var placeholder: PHObjectPlaceholder?
PHPhotoLibrary.shared().performChanges({
let listRequest = PHCollectionListChangeRequest(for: folder)
let createAlbumRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: name)
listRequest?.addChildCollections([createAlbumRequest.placeholderForCreatedAssetCollection] as NSArray)
placeholder = createAlbumRequest.placeholderForCreatedAssetCollection
}) { (success, error) in
guard let placeholder = placeholder else {
completion(nil)
return
}
let fetchResult = PHAssetCollection.fetchAssetCollections(withLocalIdentifiers: [placeholder.localIdentifier], options: nil)
let album = fetchResult.firstObject
completion(album)
}
}
/// Saves the image to a new album with the specified name
func saveImageToAlbumInRootFolder(_ albumName: String, image: UIImage?, completion: #escaping (Error?) -> Void) {
createAlbumWithName(albumName) { (album) in
guard let album = album else {
return
}
PHPhotoLibrary.shared().performChanges({
let albumChangeRequest = PHAssetCollectionChangeRequest(for: album)
let createAssetRequest = PHAssetChangeRequest.creationRequestForAsset(from: image!)
let photoPlaceholder = createAssetRequest.placeholderForCreatedAsset!
albumChangeRequest?.addAssets([photoPlaceholder] as NSArray)
}, completionHandler: { (success, error) in
if success {
completion(nil)
} else if let error = error {
// Failed with error
} else {
// Failed with no error
}
})
}
}
}
This allows you to do something like this:
let defaults = UserDefaults.standard
let identifier = defaults.string(forKey: "myFolder")!
PhotoManager.instance.fetchFolderWithIdentifier(identifier, name: "My Folder")
PhotoManager.instance.saveImageToAlbumInRootFolder("My Album", image: UIImage(named: "my_image")) { (error) in
// Handle error
}
I've looked many amazon docs but didn't find enough information to upload and download images to S3 using Swift.
How can I do that?
After doing many research I've got this working,
import AWSS3
import AWSCore
Upload:
I assume you have implemented UIImagePickerControllerDelegate already.
Step 1:
Create variable for holding url:
var imageURL = NSURL()
Create upload completion handler obj:
var uploadCompletionHandler: AWSS3TransferUtilityUploadCompletionHandlerBlock?
Step 2: Get Image URL from imagePickerController(_:didFinishPickingMediaWithInfo:):
Set value of imageURL in this delegate method:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]){
//getting details of image
let uploadFileURL = info[UIImagePickerControllerReferenceURL] as! NSURL
let imageName = uploadFileURL.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first! as String
// getting local path
let localPath = (documentDirectory as NSString).stringByAppendingPathComponent(imageName!)
//getting actual image
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
let data = UIImagePNGRepresentation(image)
data!.writeToFile(localPath, atomically: true)
let imageData = NSData(contentsOfFile: localPath)!
imageURL = NSURL(fileURLWithPath: localPath)
picker.dismissViewControllerAnimated(true, completion: nil)
}
Step 3: Call this uploadImage method after imageURL set to Upload Image to your bucket:
func uploadImage(){
//defining bucket and upload file name
let S3BucketName: String = "bucketName"
let S3UploadKeyName: String = "public/testImage.jpg"
let expression = AWSS3TransferUtilityUploadExpression()
expression.uploadProgress = {(task: AWSS3TransferUtilityTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) in
dispatch_async(dispatch_get_main_queue(), {
let progress = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
print("Progress is: \(progress)")
})
}
self.uploadCompletionHandler = { (task, error) -> Void in
dispatch_async(dispatch_get_main_queue(), {
if ((error) != nil){
print("Failed with error")
print("Error: \(error!)");
}
else{
print("Sucess")
}
})
}
let transferUtility = AWSS3TransferUtility.defaultS3TransferUtility()
transferUtility.uploadFile(imageURL, bucket: S3BucketName, key: S3UploadKeyName, contentType: "image/jpeg", expression: expression, completionHander: uploadCompletionHandler).continueWithBlock { (task) -> AnyObject! in
if let error = task.error {
print("Error: \(error.localizedDescription)")
}
if let exception = task.exception {
print("Exception: \(exception.description)")
}
if let _ = task.result {
print("Upload Starting!")
}
return nil;
}
}
Download:
func downloadImage(){
var completionHandler: AWSS3TransferUtilityDownloadCompletionHandlerBlock?
let S3BucketName: String = "bucketName"
let S3DownloadKeyName: String = "public/testImage.jpg"
let expression = AWSS3TransferUtilityDownloadExpression()
expression.downloadProgress = {(task: AWSS3TransferUtilityTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) in
dispatch_async(dispatch_get_main_queue(), {
let progress = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
print("Progress is: \(progress)")
})
}
completionHandler = { (task, location, data, error) -> Void in
dispatch_async(dispatch_get_main_queue(), {
if ((error) != nil){
print("Failed with error")
print("Error: \(error!)")
}
else{
//Set your image
var downloadedImage = UIImage(data: data!)
}
})
}
let transferUtility = AWSS3TransferUtility.defaultS3TransferUtility()
transferUtility.downloadToURL(nil, bucket: S3BucketName, key: S3DownloadKeyName, expression: expression, completionHander: completionHandler).continueWithBlock { (task) -> AnyObject! in
if let error = task.error {
print("Error: \(error.localizedDescription)")
}
if let exception = task.exception {
print("Exception: \(exception.description)")
}
if let _ = task.result {
print("Download Starting!")
}
return nil;
}
}
Ref. for upload image
Ref. for download image
Many thanks to jzorz
If all you want is to download the image, this is a much more concise and correct way to do it:
func downloadImage(bucketName: String, fileName: String, completion: (image: UIImage?, error: NSError?) -> Void) {
let transferUtility = AWSS3TransferUtility.defaultS3TransferUtility()
transferUtility.downloadDataFromBucket(bucketName, key: fileName, expression: nil) { (task, url, data, error) in
var resultImage: UIImage?
if let data = data {
resultImage = UIImage(data: data)
}
completion(image: resultImage, error: error)
}
}
func uploadFile(with resource: String, type: String) {
let key = "\(resource).\(type)"
let localImagePath = Bundle.main.path(forResource: resource, ofType: type)
let localImageUrl = URL(fileURLWithPath: localImagePath!)
let transferManager1 = AWSS3TransferUtility.default()
let expression = AWSS3TransferUtilityUploadExpression()
self.uploadCompletionHandler = { (task, error) -> Void in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
if ((error) != nil){
print("Failed with error")
print("Error: \(error!)");
}
else{
print("Sucess")
}
})
}
let transferUtility = AWSS3TransferUtility.default()
transferUtility.uploadFile(localImageUrl, bucket: "", key: key, contentType: "video/mov", expression: expression, completionHandler: uploadCompletionHandler).continueWith { (task) -> AnyObject? in
if let error = task.error {
print("Error: \(error.localizedDescription)")
}
if let _ = task.result {
print("Upload Starting!")
}
return nil;
}
}
#IBAction func uplaodVideo(){
uploadFile(with: "random", type: "mov")
}
The above answers were really helpful to me, but they're quite outdated due to a lot of the nomenclature being changed. So I'm providing an updated version of the answer based on the latest Swift frameworks.
Image Picker Controller:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
//getting details of image
let uploadFileURL = info[UIImagePickerController.InfoKey.referenceURL] as! NSURL
let imageName = uploadFileURL.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! as String
// getting local path
let localPath = (documentDirectory as NSString).appendingPathComponent(imageName!)
//getting actual image
let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
let data = image.pngData()
let imageData = image.pngData()! as NSData
let photoURL = NSURL(fileURLWithPath: localPath)
self.uploadFileURL = photoURL
self.uploadImage(inputData: imageData)
do {
let result = try data?.write(to: photoURL as URL, options: .atomic)
} catch let error {
print(error)
}
picker.dismiss(animated: true, completion: nil)
}
Upload Image:
A quick note on upload image. I hashed my filenames. This is not a necessary step, but I highly recommend to do so in the production stage just to ensure no filenames conflict in your S3 bucket.
func uploadImage(inputData: NSData) {
//defining bucket and upload file name
let S3BucketName: String = "your_bucket_name"
let hashed = SHA256.hash(data: inputData)
let S3UploadKeyName: String = hashed.compactMap { String(format: "%02x", $0) }.joined()
let expression = AWSS3TransferUtilityUploadExpression()
expression.progressBlock = {(task: AWSS3TransferUtilityTask, progress: Progress) in
print(progress.fractionCompleted)
}
self.uploadCompletionHandler = { (task, error) -> Void in
DispatchQueue.main.async(execute: {
if ((error) != nil){
print("Failed with error")
print("Error: \(error!)")
}
else{
print("Success")
}
})
}
let transferUtility = AWSS3TransferUtility.default()
transferUtility.uploadFile(self.uploadFileURL! as URL, bucket: S3BucketName, key: S3UploadKeyName, contentType: "image/jpeg", expression: expression, completionHandler: uploadCompletionHandler).continueWith { (task) -> AnyObject? in
if let error = task.error {
print("Error: \(error.localizedDescription)")
}
if let _ = task.result {
print("Upload Starting!")
// Do something with uploadTask.
}
return nil
}
}