1

I've recently been working on a project that uploads and downloads files through the Amazon S3 service, specifically a user uploaded profile picture. I am also using Amazon Cognito (Username, full name, etc), and one of the things I like about Cognito is that it saves the downloaded data locally on the phone and displays it even when the app is offline. Then, when the app goes online, it updates any data changes. Unfortunately, the same doesn't happen with S3. Every time the app starts, it has to download the profile picture from my S3 bucket before displaying them. What I want to do is have the app save the user's profile picture from the S3 bucket on the iOS device so the user can see their picture even when the app goes offline. Here is what I currently have:

func downloadImage(){

    var completionHandler: AWSS3TransferUtilityDownloadCompletionHandlerBlock?

    //downloading image
    let S3BucketName: String = "*******"
    let S3DownloadKeyName: String = self.credentialsProvider.identityId + "/profileImage.png"

    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)
            //   self.statusLabel.text = "Downloading..."
            NSLog("Progress is: %f",progress)
        })
    }

    completionHandler = { (task, location, data, error) -> Void in
        dispatch_async(dispatch_get_main_queue(), {
            if ((error) != nil){
                NSLog("Failed with error")
                NSLog("Error: %@",error!);
                //self.statusLabel.text = "Failed"
            } else {
                //self.statusLabel.text = "Success"
                self.userProfile.image = UIImage(data: data!)
                self.profileBackground.image = 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 {
            NSLog("Error: %@",error.localizedDescription);
            //  self.statusLabel.text = "Failed"
        }
        if let exception = task.exception {
            NSLog("Exception: %@",exception.description);
            //  self.statusLabel.text = "Failed"
        }
        if let _ = task.result {
            //    self.statusLabel.text = "Starting Download"
            NSLog("Download Starting!")
            // Do something with uploadTask.
        }
        return nil;
    }

} 

Thanks in advance!

iSkore
  • 7,394
  • 3
  • 34
  • 59
  • Check this out: http://stackoverflow.com/questions/6821517/save-an-image-to-application-documents-folder-from-uiview-on-ios – iSkore Mar 16 '16 at 10:03
  • That was really useful, thank you! However, what if one user were to log out and another were to log in? Would the photo still be briefly shown before being updated or would my placeholder image still be shown? Thanks for the help again. – k0mmanderBlack Mar 17 '16 at 18:07
  • So on log out you want to wipe everything out of the Application Data Path. So basically delete the local folder that all the images are stored in. – iSkore Mar 17 '16 at 18:13
  • Check out this link if you need assistance making a user log in system with AWS http://stackoverflow.com/questions/35136637/creating-a-user-authentication-system-for-ios-previously-with-parse-hopefully-a/35140150#35140150 – iSkore Mar 17 '16 at 18:14

1 Answers1

0

This is a helper to download an image from S3 Bucket and save it on local phone next time if you seek to this image. the helper will check if a local copy exists if not it will download from S3

import UIKit
import AWSCore
import AWSS3

class S3Helper: NSObject {

@objc var completionHandler: AWSS3TransferUtilityDownloadCompletionHandlerBlock?

@objc lazy var transferUtility = {
    AWSS3TransferUtility.default()
}()

let DocDirPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

func downloadImage(imageView: UIImageView!, S3Folder: String, S3FileName: String) {
    let S3DownloadKeyName: String = S3Folder + "/" + S3FileName
    imageView.image = UIImage(named: "ic_place_holder.pdf")

    let filePath = DocDirPath.appendingPathComponent(S3FileName).path
    let fileManager = FileManager.default
    if fileManager.fileExists(atPath: filePath) {
        let imageURL = self.DocDirPath.appendingPathComponent(S3FileName)
        imageView.image = UIImage(contentsOfFile: imageURL.path)!
    } else {

        let expression = AWSS3TransferUtilityDownloadExpression()
        expression.progressBlock = {(task, progress) in
            DispatchQueue.main.async(execute: {

            })
        }

        self.completionHandler = { (task, location, data, error) -> Void in
            DispatchQueue.main.async(execute: {
                if let error = error {
                    NSLog("Failed with error: \(error)")
                    //self.statusLabel.text = "Failed"
                }
                else{
                    //self.statusLabel.text = "Success"
                    imageView.image = UIImage(data: data!)

                    do{
                        let imgPath = URL(fileURLWithPath: self.DocDirPath.appendingPathComponent(S3FileName).path)
                        try (imageView.image ?? UIImage(named: "ic_place_holder.pdf")!).jpegData(compressionQuality: 1.0)?.write(to: imgPath, options: .atomic)
                    } catch let error1{
                        print(error1.localizedDescription)
                    }
                }
            })
        }

        transferUtility.downloadData(
            forKey: S3DownloadKeyName,
            expression: expression,
            completionHandler: completionHandler).continueWith { (task) -> AnyObject? in
                if let error = task.error {
                    NSLog("Error: %@",error.localizedDescription);
                    DispatchQueue.main.async(execute: {
                        //self.statusLabel.text = "Failed"
                    })
                }

                if let _ = task.result {
                    DispatchQueue.main.async(execute: {
                        //self.statusLabel.text = "Downloading..."
                    })
                    NSLog("Download Starting!")
                    // Do something with uploadTask.
                }
                return nil;
            }
    }
}

}

Firas Shrourou
  • 625
  • 8
  • 19