How do I upload and load back images from cloud kit with swift?
What attribute type do I use?
What code do I use? This is the code I use currently...
func SaveImageInCloud(ImageToSave: UIImage) {
let newRecord:CKRecord = CKRecord(recordType: "ImageRecord")
newRecord.setValue(ImageToSave, forKey: "Image")
if let database = self.privateDatabase {
database.saveRecord(newRecord, completionHandler: { (record:CKRecord!, error:NSError! ) in
if error != nil {
NSLog(error.localizedDescription)
}
else {
dispatch_async(dispatch_get_main_queue()) {
println("finished")
}
}
})
}
You need to create a CKAsset and add that to your record. You can do that with code like this:
func SaveImageInCloud(ImageToSave: UIImage) {
let newRecord:CKRecord = CKRecord(recordType: "ImageRecord")
let nsDocumentDirectory = NSSearchPathDirectory.DocumentDirectory
let nsUserDomainMask = NSSearchPathDomainMask.UserDomainMask
if let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true) {
if paths.count > 0 {
if let dirPath = paths[0] as? String {
let writePath = dirPath.stringByAppendingPathComponent("Image2.png")
UIImagePNGRepresentation(ImageToSave).writeToFile(writePath, atomically: true)
var File : CKAsset? = CKAsset(fileURL: NSURL(fileURLWithPath: writePath))
newRecord.setValue(File, forKey: "Image")
}
}
}
if let database = self.privateDatabase {
database.saveRecord(newRecord, completionHandler: { (record:CKRecord!, error:NSError! ) in
if error != nil {
NSLog(error.localizedDescription)
} else {
dispatch_async(dispatch_get_main_queue()) {
println("finished")
}
}
})
}
Here's something similar to Edwin's answer but a little more compact. I've tested this and it works well.
This example is saving "myImage" UIImageView into "mySaveRecord" CKRecord, just replace those names with your respective ones.
let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! String
let imageFilePath = documentDirectory.stringByAppendingPathComponent("lastimage")
UIImagePNGRepresentation(myImage).writeToFile(imageFilePath, atomically: true)
let asset = CKAsset(fileURL: NSURL(fileURLWithPath: imageFilePath))
mySaveRecord.setObject(asset, forKey: "ProfilePicture")
CKContainer.defaultContainer().publicCloudDatabase.saveRecord(mySaveRecord, completionHandler: {
record, error in
if error != nil {
println("\(error)")
} else {
//record saved successfully!
}
})
I created this little extension in Swift 5 to convert from UIImage to CKAsset:
extension UIImage {
func toCKAsset(name: String? = nil) -> CKAsset? {
guard let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else {
return nil
}
guard let imageFilePath = NSURL(fileURLWithPath: documentDirectory)
.appendingPathComponent(name ?? "asset#\(UUID.init().uuidString)")
else {
return nil
}
do {
try self.pngData()?.write(to: imageFilePath)
return CKAsset(fileURL: imageFilePath)
} catch {
print("Error converting UIImage to CKAsset!")
}
return nil
}
}
You can then use it as you have it in your question:
if let asset = ImageToSave.toCKAsset() {
newRecord.setObject(asset, forKey: "Image")
CKContainer.defaultContainer().publicCloudDatabase.saveRecord(newRecord, completionHandler: {
record, error in
if error != nil {
println("\(error)")
} else {
// saved successfully!
}
})
}
This answer works with Swift 2.2 & iOS 9, and separates the file creation from the upload so that you can properly test against both, since they are distinct actions with their own potential issues.
For the uploadPhoto function, the recordType variable is the value you use in your CloudKit dashboard. The "photo" key in the photo["photo"] = asset line is the field name for your record type.
func uploadPhoto(image: UIImage, recordName: String) {
let privateDB = CKContainer.defaultContainer().privateCloudDatabase
let photoID = CKRecordID(recordName: recordName)
let photo = CKRecord(recordType: recordType, recordID: photoID)
let asset = CKAsset(fileURL: writeImage(image))
photo["photo"] = asset
privateDB.saveRecord(photo) { (record, error) in
guard error == nil else {
print(error?.localizedDescription)
return
}
print("Successful")
}
}
func writeImage(image: UIImage) -> NSURL {
let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
let fileURL = documentsURL.URLByAppendingPathComponent(NSUUID().UUIDString + ".png")
if let imageData = UIImagePNGRepresentation(image) {
imageData.writeToURL(fileURL, atomically: false)
}
return fileURL
}
You can call this with the following:
uploadPhoto(UIImage(named: "foo.png")!, recordName: "bar")
You'll want to pick the Asset value type in the dashboard for this value.
newRecord.setValue(ImageToSave, forKey: "Image")
UIImage is not an allowed type on CKRecord. Your best option is to write this image out to a file, then create a CKAsset and set that on the record.
Related
I've been trying to upload audio recording right after user stops recording to the Firebase. But it doesn't do anything apart from creating a new folder named "audio".
Code I'm using for starting and stopping recording
#IBAction func recordAudio(_ sender: AnyObject) {
recordingLabel.text = "Recording in progress"
stopRecordingButton.isEnabled = true
recordButton.isEnabled = false
let dirPath = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask, true)[0] as String
let recordingName = "recordedVoice.wav"
let pathArray = [dirPath, recordingName]
let filePath = URL(string: pathArray.joined(separator: "/"))
let session = AVAudioSession.sharedInstance()
try! session.setCategory(AVAudioSessionCategoryPlayAndRecord, with:AVAudioSessionCategoryOptions.defaultToSpeaker)
try! audioRecorder = AVAudioRecorder(url: filePath!, settings: [:])
audioRecorder.delegate = self
audioRecorder.isMeteringEnabled = true
audioRecorder.prepareToRecord()
audioRecorder.record()
}
#IBAction func stopRecording(_ sender: AnyObject) {
print("Stop recording button was pressed")
recordButton.isEnabled = true
stopRecordingButton.isEnabled = false
recordingLabel.text = "Tap to Record"
audioRecorder.stop()
let audioSession = AVAudioSession.sharedInstance()
try! audioSession.setActive(false)
}
code I'm using for uploading to Firebase
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
print("finished recording")
let storageRef = Storage.storage().reference().child("audio/recordedVoice.wav")
if let uploadData = AVFileType(self.recordedVoice.wav!) {
storageRef.put(uploadData, metadata: nil) {(metadata, error) in
if error != nil {
print(error)
return
}
}
}
}
Please help me!
Try:
let audioName = NSUUID().uuidString //You'll get unique audioFile name
let storageRef = Storage.storage().reference().child("audio").child(audioName)
let metadata = StorageMetadata()
metadata.contentType = "audio/wav"
if let uploadData = AVFileType(self.recordedVoice.wav!) {
storageRef.putData(uploadData, metadata: metadata) { (metadata, err) in
if err != nil {
//print(err)
return
}
if let _ = metadata?.downloadURL()?.absoluteString {
print("uploading done!")
}
}
}
so I have been working on this for hours and here is my answer:
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
func getFileURL() -> URL {
let path = getDocumentsDirectory()
let filePath = path.appendingPathComponent(K.fileName)
return filePath
}
let referance = storage.reference()
let mediaFolder = referance.child("media")
let id = UUID().uuidString // using uuid to give uniq names to audiofiles preventing overwrite
let mediaRef = mediaFolder.child(id + K.fileName) // creating file referance using uuid + filename
let path = getFileURL() // getting filepath
do {
let data = try Data(contentsOf: path) // getting data from filepath
mediaRef.putData(data) { metadata, error in
if error != nil {
self.showAlert(title: "Error", message: error?.localizedDescription, cancelButtonTitle: "cancel", handler: nil)
} else {
mediaRef.downloadURL { url, error in
let url = url?.absoluteString
print(url)
}
}
}
print("record has come")
} catch {
print("error cant get audio file")
}
I'm relatively new at coding and still learning. So that my answer may not be the best and shortest. But This worked for me.
I am trying to complet an an action after the URLSession resumes.
So I am downloading several images from my server with the url, which all works good. But now I am trying to save those images to the disk after I have finished downloading them.
Problem
Now I can save them inside the same query while downloading them but I would prefer not too as it makes my query slower.
So I have added a completion handler to my func with the query, but when I save the images to the disk in that block it works but I cannot do anything with my screen as the query has not resumed yet it is blocked from touches I guess...
Now I would like to be able to call my func to save the images to the disk straight after the query has been resumed.... Anyone have any idea?
If someone needs more explanation or to see code just drop a comment below
Many thanks in advance to anyone that can help!
Code for downloading
func loadPosts(completionHandler: #escaping (Bool) -> ()) {
pageNumber = 1
appDelegate.setNetworkActivityIndicatorVisible(true)
let id = user!["id"] as! String
let url = URL(string: "http://************/Files/Posts.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let body = "id=\(id)&caption=&uuid=&page="
request.httpBody = body.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request, completionHandler: { (data:Data?, response:URLResponse?, error:Error?) in
DispatchQueue.global(qos: .background).async {
if error == nil {
let oldImageArray = self.cellContentArray
self.cellContentArray.removeAll(keepingCapacity: false)
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
guard let parseJSON = json else {
print("Error while parsing")
return
}
guard let posts = parseJSON["Posts"] as? [AnyObject] else {
print("Error while parseJSONing")
return
}
for element in posts {
// here I download the stuff and it to my Array, too long and no point to show here
}
let oldImageSet = Set(oldImageArray.map({return $0.uuid}))
let newImageSet = Set(self.cellContentArray.map({return $0.uuid}))
let addedImages = newImageSet.subtracting(oldImageSet)
let addedImageSections = Array(addedImages).map{ self.cellContentArray.map({return $0.uuid}).index(of: $0)! }
let addedImageIndexSet = IndexSet(addedImageSections)
let removedImages = oldImageSet.subtracting(newImageSet)
let removedImageSections = Array(removedImages).map{ oldImageArray.map({return $0.uuid}).index(of: $0)! }
let removedImageIndexSet = IndexSet(removedImageSections)
if !addedImageIndexSet.isEmpty {
if oldImageArray.count >= 5 {
self.lastUUIDImage = oldImageArray[4].uuid
} else {
}
self.coreDataShit()
}
DispatchQueue.main.async{
print(placeholderImage.count)
if placeholderImage.count > 5 {
placeholderImage.removeFirst(placeholderImage.count - 5)
}
print("finished")
self.customView.isHidden = true
if posts.count >= 5 {
self.tableView.addInfiniteScroll { [weak self] (scrollView) -> Void in
self?.loadMore()
}}
self.activityView.stopAnimating()
self.internetView.removeFromSuperview()
self.tableView.beginUpdates()
if !addedImageIndexSet.isEmpty {
self.tableView.insertSections(addedImageIndexSet, with: .top)
}
if !removedImageIndexSet.isEmpty {
self.tableView.deleteSections(removedImageIndexSet, with: .bottom)
}
self.tableView.endUpdates()
self.tableView.finishInfiniteScroll()
self.refresher.endRefreshing()
appDelegate.setNetworkActivityIndicatorVisible(false)
completionHandler(true)
}
} catch {
DispatchQueue.main.async {
self.tableView.removeInfiniteScroll()
self.customView.isHidden = false
self.refresher.endRefreshing()
self.tableView.reloadData()
}
}
} else {
DispatchQueue.main.async(execute: {
let message = error!.localizedDescription
appDelegate.infoView(message: message, color: smoothRedColor)
})
}
}
})
task.resume()
}
Saving Image
self.loadPosts(completionHandler: { (true) in
print("completion")
let sections = self.tableView.numberOfSections
for i in 0..<sections {
self.rows += self.tableView.numberOfRows(inSection: i)
}
print(self.rows)
if self.rows <= 5 {
print("less than 5")
print(self.rows)
var i = 0
for element in self.cellContentArray {
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let dirPath = "\(path)/images"
let url = NSURL(fileURLWithPath: dirPath)
let filePath = url.appendingPathComponent("\(element.uuid).jpg")?.path
let fileManager = FileManager.default
if fileManager.fileExists(atPath: filePath!) {
print("File exsists")
} else {
print("File doesn't exsist")
DispatchQueue.main.async {
let url = NSURL(string: element.fullImage!)! // convert path str to url
let imageData = NSData(contentsOf: url as URL) // get data via url and assigned imageData
let imageName = element.uuid
let saveImages = FileSaveHelper(fileName: imageName, fileExtension: .JPG, subDirectory: "images", directory: .documentDirectory)
do {
guard let image = UIImage.sd_image(with: imageData as Data!) else {
print("Error getting image")
return
}
try saveImages.saveFile(image: image)
self.saveNewImagePath(imageLink: imageName, uuid: imageName)
self.removeImage(itemName: "file\(i)", fileExtension: "jpg")
self.removeImage(itemName: self.lastUUIDImage, fileExtension: "jpg")
i += 1
} catch {
print(error)
}
}
}
}
}
})
Image in tableView Cell
self.postImage.sd_setImage(with: URL(string: content.fullImage!), placeholderImage: placeHolder, options: .retryFailed) { (image:UIImage?, error:Error?, cached:SDImageCacheType, url:URL?) in
}
In your code of saving image this line of code is blocking you UI
let imageData = NSData(contentsOf: url as URL) // get data via url and assigned imageData
This is not proper way to download image from server, you should download image asynchronously using URLSession
I'm trying to upload an image to a bucket S3 AWS, I am using the following code. but do I use it to upload to an image stored in a variable or imageView.image?
let ext = "jpg"
let imageURL = NSBundle.mainBundle().URLForResource("imagename", withExtension: ext)
print("imageURL:\(imageURL)")
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest.body = imageURL
uploadRequest.key = NSProcessInfo.processInfo().globallyUniqueString + "." + ext
uploadRequest.bucket = S3BucketName
uploadRequest.contentType = "image/" + ext
let transferManager = AWSS3TransferManager.defaultS3TransferManager()
transferManager.upload(uploadRequest).continueWithBlock { (task) -> AnyObject! in
if let error = task.error {
print("Upload failed ❌ (\(error))")
}
if let exception = task.exception {
print("Upload failed ❌ (\(exception))")
}
if task.result != nil {
let s3URL = NSURL(string: "http://s3.amazonaws.com/\(self.S3BucketName)/\(uploadRequest.key!)")!
print("Uploaded to:\n\(s3URL)")
}
else {
print("Unexpected empty result.")
}
return nil
}
AWSS3TransferManager is deprecated. Use AWSS3TransferUtility instead.
The transfer utility provides methods for both single-part and
multipart uploads. When a transfer uses multipart upload, the data is
chunked into a number of 5 MB parts which are transferred in parallel
for increased speed.
func uploadFile(withImage image: UIImage) {
let access = "YOUR ACCESS KEY"
let secret = "YOUR SECRET KEY"
let credentials = AWSStaticCredentialsProvider(accessKey: access, secretKey: secret)
let configuration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: credentials)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let s3BucketName = "YOUR BUCKET NAME"
let compressedImage = image.resizedImage(newSize: CGSize(width: 80, height: 80))
let data: Data = compressedImage.pngData()!
let remoteName = generateRandomStringWithLength(length: 12)+"."+data.format
print("REMOTE NAME : ",remoteName)
let expression = AWSS3TransferUtilityUploadExpression()
expression.progressBlock = { (task, progress) in
DispatchQueue.main.async(execute: {
// Update a progress bar
})
}
var completionHandler: AWSS3TransferUtilityUploadCompletionHandlerBlock?
completionHandler = { (task, error) -> Void in
DispatchQueue.main.async(execute: {
// Do something e.g. Alert a user for transfer completion.
// On failed uploads, `error` contains the error object.
})
}
let transferUtility = AWSS3TransferUtility.default()
transferUtility.uploadData(data, bucket: s3BucketName, key: remoteName, contentType: "image/"+data.format, expression: expression, completionHandler: completionHandler).continueWith { (task) -> Any? in
if let error = task.error {
print("Error : \(error.localizedDescription)")
}
if task.result != nil {
let url = AWSS3.default().configuration.endpoint.url
let publicURL = url?.appendingPathComponent(S3BucketName).appendingPathComponent(remoteName)
if let absoluteString = publicURL?.absoluteString {
// Set image with URL
print("Image URL : ",absoluteString)
}
}
return nil
}
}
For generating random strings for remote name.
func generateRandomStringWithLength(length: Int) -> String {
let randomString: NSMutableString = NSMutableString(capacity: length)
let letters: NSMutableString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var i: Int = 0
while i < length {
let randomIndex: Int = Int(arc4random_uniform(UInt32(letters.length)))
randomString.append("\(Character( UnicodeScalar( letters.character(at: randomIndex))!))")
i += 1
}
return String(randomString)
}
For resizing the image and data formatting. Use below Image and Data extensions.
extension UIImage {
func resizedImage(newSize: CGSize) -> UIImage {
guard self.size != newSize else { return self }
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0);
self.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
}
extension Data {
var format: String {
let array = [UInt8](self)
let ext: String
switch (array[0]) {
case 0xFF:
ext = "jpg"
case 0x89:
ext = "png"
case 0x47:
ext = "gif"
case 0x49, 0x4D :
ext = "tiff"
default:
ext = "unknown"
}
return ext
}
}
I Have modified your code, try this
let ext = "jpg"
let imageURL = NSBundle.mainBundle().URLForResource("imagename", withExtension: ext)
print("imageURL:\(imageURL)")
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest.body = imageURL
uploadRequest.key = "\(NSProcessInfo.processInfo().globallyUniqueString).\(ext)"
uploadRequest.bucket = S3BucketName
uploadRequest.contentType = "image/\(ext)"
let transferManager = AWSS3TransferManager.defaultS3TransferManager()
transferManager.upload(uploadRequest).continueWithBlock { (task) -> AnyObject! in
if let error = task.error {
print("Upload failed ❌ (\(error))")
}
if let exception = task.exception {
print("Upload failed ❌ (\(exception))")
}
if task.result != nil {
let s3URL = NSURL(string: "http://s3.amazonaws.com/\(self.S3BucketName)/\(uploadRequest.key!)")!
print("Uploaded to:\n\(s3URL)")
}
else {
print("Unexpected empty result.")
}
return nil
}
or you can use my code below to upload to AWS s3, its worked fine for me. This code is written in swift 3.
func uploadButtonPressed(_ sender: AnyObject) {
if documentImageView.image == nil {
// Do something to wake up user :)
} else {
let image = documentImageView.image!
let fileManager = FileManager.default
let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("\(imageName!).jpeg")
let imageData = UIImageJPEGRepresentation(image, 0.99)
fileManager.createFile(atPath: path as String, contents: imageData, attributes: nil)
let fileUrl = NSURL(fileURLWithPath: path)
var uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest?.bucket = "BucketName"
uploadRequest?.key = "key.jpeg"
uploadRequest?.contentType = "image/jpeg"
uploadRequest?.body = fileUrl as URL!
uploadRequest?.serverSideEncryption = AWSS3ServerSideEncryption.awsKms
uploadRequest?.uploadProgress = { (bytesSent, totalBytesSent, totalBytesExpectedToSend) -> Void in
DispatchQueue.main.async(execute: {
self.amountUploaded = totalBytesSent // To show the updating data status in label.
self.fileSize = totalBytesExpectedToSend
})
}
let transferManager = AWSS3TransferManager.default()
transferManager?.upload(uploadRequest).continue(with: AWSExecutor.mainThread(), withSuccessBlock: { (taskk: AWSTask) -> Any? in
if taskk.error != nil {
// Error.
} else {
// Do something with your result.
}
return nil
})
}
}
Thanks :)
We should use AWSS3TransferUtility now because AWSS3TransferManagerUploadRequest is deprecated, here is the jpeg upload function in Swift 4.2 but it can be easily changed for any data type:
func uploadS3(image: UIImage,
name: String,
progressHandler: #escaping (Progress) -> Void,
completionHandler: #escaping (Error?) -> Void) {
guard let data = UIImageJPEGRepresentation(image, Constants.uploadImageQuality) else {
DispatchQueue.main.async {
completionHandler(NetErrors.imageFormatError) // Replace your error
}
return
}
let credentialsProvider = AWSStaticCredentialsProvider(accessKey: Constants.accessKeyS3, secretKey: Constants.secretKeyS3)
let configuration = AWSServiceConfiguration(region: Constants.regionS3, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let expression = AWSS3TransferUtilityUploadExpression()
expression.progressBlock = { task, progress in
DispatchQueue.main.async {
progressHandler(progress)
}
}
AWSS3TransferUtility.default().uploadData(
data,
bucket: Constants.bucketS3,
key: name,
contentType: "image/jpg",
expression: expression) { task, error in
DispatchQueue.main.async {
completionHandler(error)
}
print("Success")
}.continueWith { task -> AnyObject? in
if let error = task.error {
DispatchQueue.main.async {
completionHandler(error)
}
}
return nil
}
}
Do not forget to define or change Constants in the code. If you don't want to give public access, you should also define a user in IAM, and put this code in your bucket policy:
{
"Version": "2012-10-17",
"Id": "S3AccessPolicy",
"Statement": [
{
"Sid": "GiveAppAccess",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:user/YOUR_USER"
},
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::YOUR_BUCKET/*"
}
]
}
This is the latest code based on SWIFT 4 syntax
I am using the code of #Karthick Selvaraj.
I think now its help to other developers to understand new syntax
func uploadButtonPressed() {
if myimageView.image == nil {
// Do something to wake up user :)
} else {
let image = myimageView.image!
let fileManager = FileManager.default
let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("test3.jpeg")
let imageData = UIImageJPEGRepresentation(image, 0)
fileManager.createFile(atPath: path as String, contents: imageData, attributes: nil)
let fileUrl = NSURL(fileURLWithPath: path)
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest?.bucket = "<Your Bucket Name>"
uploadRequest?.key = "<Image Name>"
uploadRequest?.contentType = "image/jpeg"
uploadRequest?.body = fileUrl as URL!
uploadRequest?.serverSideEncryption = AWSS3ServerSideEncryption.awsKms
uploadRequest?.uploadProgress = { (bytesSent, totalBytesSent, totalBytesExpectedToSend) -> Void in
DispatchQueue.main.async(execute: {
// print("totalBytesSent",totalBytesSent)
// print("totalBytesExpectedToSend",totalBytesExpectedToSend)
// self.amountUploaded = totalBytesSent // To show the updating data status in label.
// self.fileSize = totalBytesExpectedToSend
})
}
let transferManager = AWSS3TransferManager.default()
transferManager.upload(uploadRequest!).continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask<AnyObject>) -> Any? in
if task.error != nil {
// Error.
print("error")
} else {
// Do something with your result.
print("No error Upload Done")
}
return nil
})
}
}
Enjoy !!!
This is image uploading using AWS S3 bucket this below code i implemented image uploading from gallery to uploading
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
if(picker.sourceType == UIImagePickerControllerSourceType.PhotoLibrary)
{
selectedImageUrl = info[UIImagePickerControllerReferenceURL] as! NSURL
myImageViewC.image = info[UIImagePickerControllerOriginalImage] as? UIImage
myImageViewC.backgroundColor = UIColor.clearColor()
myImageViewC.contentMode = UIViewContentMode.ScaleAspectFit
self.dismissViewControllerAnimated(true, completion: nil)
startUploadingImage()
}
else if(picker.sourceType == UIImagePickerControllerSourceType.Camera)
{
myImageViewC.image = info[UIImagePickerControllerOriginalImage] as? UIImage
myImageViewC.backgroundColor = UIColor.clearColor()
myImageViewC.contentMode = UIViewContentMode.ScaleAspectFit
self.dismissViewControllerAnimated(true, completion: nil)
myActivityIndicator.startAnimating()
let S3BucketName = "streetsmartb2/sai"
let date3 = NSDate()
let timeInMi = "\(CLongLong((floor(date3.timeIntervalSince1970 * 1000))))"
let S3UploadKeyName = "File.jpg\(timeInMi)"
//print("value1:\(S3UploadKeyName)")
//settings temp location for image
let imageName = NSURL.fileURLWithPath(NSTemporaryDirectory() + S3UploadKeyName).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 = UIImageJPEGRepresentation(image, 0.5)
let data = CreateTeamViewController().resizeImage(image)
data.writeToFile(localPath, atomically: true)
//let imageData = NSData(contentsOfFile: localPath)!
let photoURL = NSURL(fileURLWithPath: localPath)
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest.body = photoURL
uploadRequest.key = S3UploadKeyName
uploadRequest.bucket = S3BucketName
uploadRequest.contentType = "image/jpeg"
let transferManager = AWSS3TransferManager.defaultS3TransferManager()
// Perform file upload
transferManager.upload(uploadRequest).continueWithBlock { (task) -> AnyObject! in
if let error = task.error {
print("Upload failed with error: (\(error.localizedDescription))")
dispatch_async(dispatch_get_main_queue()) {
// self.returnToAddView()
self.myActivityIndicator.stopAnimating()
CreateTeamViewController().displayAlertMessage("Error uploading Image")
}
}
if let exception = task.exception {
print("Upload failed with exception (\(exception))")
dispatch_async(dispatch_get_main_queue()) {
// self.returnToAddView()
self.myActivityIndicator.stopAnimating()
CreateTeamViewController().displayAlertMessage("Error uploading Image")
}
}
if task.result != nil {
// Remove locally stored file
self.remoteImageWithUrl(uploadRequest.key!)
let s3URL = NSURL(string: "https://s3.amazonaws.com/\(S3BucketName)/\(uploadRequest.key!)")!
// print("Uploaded to:\n\(s3URL)")
dispatch_async(dispatch_get_main_queue()) {
// self.returnToAddView()
self.myActivityIndicator.stopAnimating()
self.createTeamImageButton?.setImage(self.loadImage, forState: .Normal)
self.uploadedImageURL = (s3URL.URLString)
// self.teamImageNameCreate = self.uploadedImageURL
// self.createTeamImageButton.sd_setImageWithURL(NSURL(string: self.uploadedImageURL)!, forState: .Normal, placeholderImage: UIImage(named: "no_image_one.jpg"))
let url = NSURL.init(string: self.uploadedImageURL)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// do some task
let imagedata = NSData(contentsOfURL: url!)
if let imageObj = UIImage.init(data: imagedata!) {
self.createTeamPic = imageObj
}
dispatch_async(dispatch_get_main_queue()) {
self.createTeamImageButton?.setImage(self.createTeamPic, forState: .Normal)
}
}
}
}
else {
// print("Unexpected empty result.")
}
return nil
}
}
}
I'm updating SwiftData from Swift 1.2 to Swift 2 and after some changes and corrections I'm still having an error that I can't understand why it's happening.
The code goes as the following:
public static func saveUIImage(image: UIImage) -> String? {
let docsPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as String
let imageDirPath = docsPath.stringByAppendingPathComponent("SwiftDataImages")
if !NSFileManager.defaultManager().fileExistsAtPath(imageDirPath) {
do {
try NSFileManager.defaultManager().createDirectoryAtPath(imageDirPath, withIntermediateDirectories: false, attributes: [:])
} catch {
print("Error creating SwiftData image folder")
return nil
}
}
let imageID = NSUUID().UUIDString
let imagePath = (imageDirPath as NSString).stringByAppendingPathComponent(imageID)
let imageAsData = UIImagePNGRepresentation(image)
if !imageAsData!.writeToFile(imagePath, atomically: true) {
print("Error saving image")
return nil
}
return imageID
}
On the 'do {' line Xcode is throwing the following error:
Cannot invoke 'createDirectoryAtPath' with an argument list of type '(String, withIntermediateDirectories: Bool, attributes: _, error: _)'
Any tips of why this is happening? It's driving me crazy.
Kind regards, and thanks in advance.
;)
In my Xcode 7.2 there is no:
let imageDirPath = docsPath.stringByAppendingPathComponent("SwiftDataImages")
So I tried this code and it compiles fine:
public func saveUIImage(image: UIImage) -> String? {
let docsPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as String
let imageDirPath = NSURL(string: docsPath)?.URLByAppendingPathComponent("SwiftDataImages")
if !NSFileManager.defaultManager().fileExistsAtPath(imageDirPath!.absoluteString) {
do {
try NSFileManager.defaultManager().createDirectoryAtPath(imageDirPath!.absoluteString, withIntermediateDirectories: false, attributes: [:])
} catch {
print("Error creating SwiftData image folder")
return nil
}
}
let imageID = NSUUID().UUIDString
let imagePath = (imageDirPath!.absoluteString as NSString).stringByAppendingPathComponent(imageID)
let imageAsData = UIImagePNGRepresentation(image)
if !imageAsData!.writeToFile(imagePath, atomically: true) {
print("Error saving image")
return nil
}
return imageID
}
Apple highly recommends to use the URL related API of NSFileManager and NSData
public func saveUIImage(image: UIImage) -> String? {
let fileManager = NSFileManager.defaultManager()
let docsURL = try! fileManager.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
let imageDirURL = docsURL.URLByAppendingPathComponent("SwiftDataImages")
if !fileManager.fileExistsAtPath(imageDirURL.path!) {
do {
try fileManager.createDirectoryAtURL(imageDirURL, withIntermediateDirectories: false, attributes:nil)
} catch let error as NSError{
print("Error creating SwiftData image folder", error)
return nil
}
}
let imageID = NSUUID().UUIDString
let imageURL = imageDirURL.URLByAppendingPathComponent(imageID)
let imageAsData = UIImagePNGRepresentation(image)
if !imageAsData!.writeToURL(imageURL, atomically: true) {
print("Error saving image")
return nil
}
return imageID
}
I am using this code to store an image in icloud, but what code do i use to retrieave it and place it in a UIImageView? I've tried everything, but it wont work?
func SaveImageInCloud(ImageToSave: UIImage) {
let newRecord:CKRecord = CKRecord(recordType: "ImageRecord")
let nsDocumentDirectory = NSSearchPathDirectory.DocumentDirectory
let nsUserDomainMask = NSSearchPathDomainMask.UserDomainMask
if let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true) {
if paths.count > 0 {
if let dirPath = paths[0] as? String {
let writePath = dirPath.stringByAppendingPathComponent("Image2.png")
UIImagePNGRepresentation(ImageToSave).writeToFile(writePath, atomically: true)
var File : CKAsset? = CKAsset(fileURL: NSURL(fileURLWithPath: writePath))
newRecord.setValue(File, forKey: "Image")
}
}
}
if let database = self.privateDatabase {
database.saveRecord(newRecord, completionHandler: { (record:CKRecord!, error:NSError! ) in
if error != nil {
NSLog(error.localizedDescription)
} else {
dispatch_async(dispatch_get_main_queue()) {
println("finished")
}
}
})
}
Just read the CKRecord that you wrote and you can get the CKAsset by reading the key Image. You can get a UIImage using the code below.
var file : CKAsset? = record.objectForKey("Image")
func image() -> UIImage? {
if let file = file {
if let data = NSData(contentsOfURL: file.fileURL) {
return UIImage(data: data)
}
}
return nil
}
After downloading the CKAsset, we need to convert the CKAsset to a UIImage. We can use the following extension (Swift 4 code):
extension CKAsset {
func toUIImage() -> UIImage? {
if let data = NSData(contentsOf: self.fileURL) {
return UIImage(data: data as Data)
}
return nil
}
}
You have to first have a way of finding the specific ImageRecord that you want to retrieve. Assuming that you have the RecordID for the ImageRecord you saved (you can get this from the record in the saveRecord completion block) you can do:
if let database = privateDatabase {
database.fetchRecordWithID(recordID, completionHandler: { (record, error) -> Void in
guard let record = record else {
print("Error retrieving record", error)
return
}
guard let asset = record["Image"] as? CKAsset else {
print("Image missing from record")
return
}
guard let imageData = NSData(contentsOfURL: asset.fileURL) else {
print("Invalid Image")
return
}
let image = UIImage(data: imageData)
imageView.image = image
})
}
(Although you would definitely want to be doing some error handling where those print()s are)
If you don't save the recordID (or probably better: the recordID.recordName so you can make another CKRecordID later), you would need some other way of finding which record you are looking for. If that's the case you'd want to look into using CKDatabase's performQuery(_:inZoneWithID:completionHandler:) method.