I have a question,and I want to show the progressView when I download the Image to my local file
I write a function to download Image, and take other question as reference.
but I don't know how to use URLSessionDownloadTak or other download progress function in my function.
This is my download function code:
func ImageFromUrl(imageView:UIImageView,url:String,chatroomId:String) {
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("\(Image)/")
// create a name for your image
let fileName = url + ".jpg"
let fileURL = documentsDirectoryURL.appendingPathComponent(fileName)
let urlString = URL(string: url)
if let image = UIImage(contentsOfFile: fileURL.path)
{
imageView.image = image
return
}
DispatchQueue.global().async {
let data = try? Data(contentsOf: urlString!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
if data != nil
{
if let image = UIImage(data: data!)
{
if !FileManager.default.fileExists(atPath: fileURL.path) {
if let jpegData = UIImageJPEGRepresentation(image, 0.001)
{
do {
try jpegData.write(to: fileURL, options: .atomic)
} catch {
debug(object: error)
}
}
} else {
debug(object:"file already exists")
}
DispatchQueue.main.async {
imageView.image = image//UIImage(data: data!)
}
}
}
}
}
If you want a simple solution instead of NSURLSession, I would suggest Alamofire. It has a simple method to do this kind of task.
For more information https://github.com/Alamofire/Alamofire
Alamofire.download(urlString)
.downloadProgress { progress in
print("Download Progress: \(progress.fractionCompleted)")
}
.responseData { response in
if let data = response.result.value {
let image = UIImage(data: data)
}
}
Related
I want to attach an image to my local notifications given an image URL. This is the extension to create an attachment:
import UserNotifications
extension UNNotificationAttachment {
static func create(identifier: String, image: UIImage, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
let fileManager = FileManager.default
let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
let tmpSubFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true)
do {
try fileManager.createDirectory(at: tmpSubFolderURL, withIntermediateDirectories: true, attributes: nil)
let imageFileIdentifier = identifier+".png"
let fileURL = tmpSubFolderURL.appendingPathComponent(imageFileIdentifier)
guard let imageData = UIImagePNGRepresentation(image) else {
return nil
}
try imageData.write(to: fileURL)
let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier, url: fileURL, options: options)
return imageAttachment } catch {
print("error " + error.localizedDescription)
}
return nil
}
}
When I schedule a new notification, I use it like this:
// url of the image such as http://www.unsplash.com/image.png
let data = try? Data(contentsOf: url)
guard let myImage = UIImage(data: data!) else { return }
if let attachment = UNNotificationAttachment.create(identifier: key, image: myImage, options: nil) {
content.attachments = [attachment]
}
Creating a notification like this freezes the application for a few seconds because the app downloads the image synchronously. I have also tried to use DispatchQueue but it didn't change anything. What did I do wrong?
Your code downloads an image, parses it to create a UIImage, converts the image back to a block of PNG data, then writes this data to a temporary file.
You can skip the step where you create the UIImage and convert it back to a file.
Try using URLSession and URLDataTask:
let fileURL = ...
let task = URLSession.shared.dataTask(with: url) { (data, _, _) in
do {
try imageData.write(to: fileURL)
let attachment = UNNotificationAttachment.create(identifier: key, image: myImage, options: nil)
// call closure to call back with attachment and/or error
}
catch let ex {
// call closure with error
}
}
task.resume()
I've left out some error handling and other details, but this should give you the general idea of what's required to do it asynchronously. URLSessions use GCD to perform asynchronous networking.
Download the image asynchronously using Alamofire then try to show it.
let destination: DownloadRequest.DownloadFileDestination = {
_, _ in
var documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
documentsURL.appendPathComponent("image.jpg")
return (documentsURL, [.removePreviousFile, .createIntermediateDirectories])
}
Alamofire.download(url, to: destination).response {
response in
// do whatever you want with your image, for example if it is an audio file:
do {
self.player = try AVAudioPlayer(contentsOf: URL(string: "\(response.destinationURL!)")!)
self.player.volume = 1.0
self.player.play()
} catch {
print(error)
}
}
I would like to save images from a URL and then use them inside my app.
I saved them in variables but how can I make them persist until the user deletes the app ?
Here is the code for saving images in variables
let backgroundURL:NSURL? = NSURL(string: "http://i.imgur.com/4AiXzf8.jpg")
DispatchQueue.global(qos: .userInitiated).async {
let backgroundData:NSData? = NSData(contentsOf: backgroundURL as! URL)
DispatchQueue.main.async {
if (backgroundData != nil) {
background = UIImage(data: backgroundData! as Data
}
}
}
How can I save the background image to persist ?
Thank you!
For Swift 3
// Assuming background is UIImage
if let image = background {
if let data = UIImagePNGRepresentation(image) {
let filename = getDocumentsDirectory().appendingPathComponent("copy.png")
try? data.write(to: filename)
}
}
That call to getDocumentsDirectory()
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
I would suggest you to store image in your document directory the below code you will be able to use after you downloaded image and converted as UIImage from NSData
Swift 2.3
let documentsDirectoryURL = try! NSFileManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
// Name of Image you want to store
let fileURL = documentsDirectoryURL.URLByAppendingPathComponent("ImageName.jpg")
if !NSFileManager.defaultManager().fileExistsAtPath(fileURL.path!) {
if UIImageJPEGRepresentation(image, 1.0)!.writeToFile(fileURL.path!, atomically: true) {
print("Image saved")
} else {
print("error saving Image")
}
} else {
print("Image name already exists")
}
And here is how you can get image
let fileManager = NSFileManager.defaultManager()
let imagePAth = (self.getDirectoryPath() as NSString).stringByAppendingPathComponent("imageName.jpg")
if fileManager.fileExistsAtPath(imagePAth){
let myImage: UIImage = UIImage(contentsOfFile: imagePAth)
}
else{
print("No Such Image")
}
I have a simple ImagePicker for the user to select, or take, a profile picture. I want to save this image to the Home Directory for easy loading later.
The problem is with the Image type not being set.
//Save Image
_ = PPimagePicked.image
let imageData = UIImageJPEGRepresentation(PPimagePicked.image!, 0.6)
let compressedJPGImage = UIImage(data: imageData!)
UIImageWriteToSavedPhotosAlbum(compressedJPGImage!, nil, nil, nil)
// Get Document Root Path
let path = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("Documents/profile.jpg")
do {
//Save image to Root
try imageData?.write(to: path, options: .atomic)
print("Saved To Root")
} catch let error {
print(error)
}
The exact Error is :
"[Generic] Creating an image format with an unknown type is an error"
Please try this code i am using it in swift 2.2. Below method includes for both UIImageJPEGRepresentation, UIImagePNGRepresentation
if let image = UIImage(named: "example.png") {
if let data = UIImageJPEGRepresentation(image, 0.8) {
let filename = getDocumentsDirectory().appendingPathComponent("copy.png")
try? data.write(to: filename)
}
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
if let image = UIImage(named: "example.png") {
if let data = UIImagePNGRepresentation(image) {
let filename = getDocumentsDirectory().appendingPathComponent("copy.png")
try? data.write(to: filename)
}
}
try converting the image to image data
let imageCapture = UIImage(data: dataImage)!
UIImageWriteToSavedPhotosAlbum((image: imageCapture), nil, nil, nil)
I am saving an image using saveImage.
func saveImage (image: UIImage, path: String ) -> Bool{
let pngImageData = UIImagePNGRepresentation(image)
//let jpgImageData = UIImageJPEGRepresentation(image, 1.0) // if you want to save as JPEG
print("!!!saving image at: \(path)")
let result = pngImageData!.writeToFile(path, atomically: true)
return result
}
New info:
Saving file does not work properly ("[-] ERROR SAVING FILE" is printed)--
// save your image here into Document Directory
let res = saveImage(tempImage, path: fileInDocumentsDirectory("abc.png"))
if(res == true){
print ("[+] FILE SAVED")
}else{
print ("[-] ERROR SAVING FILE")
}
Why doesn't the saveImage function save the image? Access rights?
Older info:
The debug info says:
!!!saving image at: file:///var/mobile/Applications/BDB992FB-E378-4719-B7B7-E9A364EEE54B/Documents/tempImage
Then I retrieve this location using
fileInDocumentsDirectory("tempImage")
The result is correct.
Then I am loading the file using this path
let image = UIImage(contentsOfFile: path)
if image == nil {
print("missing image at: \(path)")
}else{
print("!!!IMAGE FOUND at: \(path)")
}
The path is correct, but the message is "missing image at..". Is the file somehow inaccessible or not stored? What can be a reason for this behavior?
I am testing this code on iphone 4 with ios 7 and iphone 5 with ios 7 simulator.
Edit:
1. The fileInDocumentsDirectory function
func fileInDocumentsDirectory(filename: String) -> String {
let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let fileURL = documentsURL.URLByAppendingPathComponent(filename).absoluteString
return fileURL
}
This function will save an image in the documents folder:
func saveImage(image: UIImage) -> Bool {
guard let data = UIImageJPEGRepresentation(image, 1) ?? UIImagePNGRepresentation(image) else {
return false
}
guard let directory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) as NSURL else {
return false
}
do {
try data.write(to: directory.appendingPathComponent("fileName.png")!)
return true
} catch {
print(error.localizedDescription)
return false
}
}
To use:
let success = saveImage(image: UIImage(named: "image.png")!)
This function will get that image:
func getSavedImage(named: String) -> UIImage? {
if let dir = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) {
return UIImage(contentsOfFile: URL(fileURLWithPath: dir.absoluteString).appendingPathComponent(named).path)
}
return nil
}
To use:
if let image = getSavedImage(named: "fileName") {
// do something with image
}
iOS 13+ Swift 5.1
iOS 12 introduced some API Changes.
func saveImage(imageName: String, image: UIImage) {
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileName = imageName
let fileURL = documentsDirectory.appendingPathComponent(fileName)
guard let data = image.jpegData(compressionQuality: 1) else { return }
//Checks if file exists, removes it if so.
if FileManager.default.fileExists(atPath: fileURL.path) {
do {
try FileManager.default.removeItem(atPath: fileURL.path)
print("Removed old image")
} catch let removeError {
print("couldn't remove file at path", removeError)
}
}
do {
try data.write(to: fileURL)
} catch let error {
print("error saving file with error", error)
}
}
func loadImageFromDiskWith(fileName: String) -> UIImage? {
let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
if let dirPath = paths.first {
let imageUrl = URL(fileURLWithPath: dirPath).appendingPathComponent(fileName)
let image = UIImage(contentsOfFile: imageUrl.path)
return image
}
return nil
}
Details
Xcode Version 10.2 (10E125), Swift 5
Solution
// save
extension UIImage {
func save(at directory: FileManager.SearchPathDirectory,
pathAndImageName: String,
createSubdirectoriesIfNeed: Bool = true,
compressionQuality: CGFloat = 1.0) -> URL? {
do {
let documentsDirectory = try FileManager.default.url(for: directory, in: .userDomainMask,
appropriateFor: nil,
create: false)
return save(at: documentsDirectory.appendingPathComponent(pathAndImageName),
createSubdirectoriesIfNeed: createSubdirectoriesIfNeed,
compressionQuality: compressionQuality)
} catch {
print("-- Error: \(error)")
return nil
}
}
func save(at url: URL,
createSubdirectoriesIfNeed: Bool = true,
compressionQuality: CGFloat = 1.0) -> URL? {
do {
if createSubdirectoriesIfNeed {
try FileManager.default.createDirectory(at: url.deletingLastPathComponent(),
withIntermediateDirectories: true,
attributes: nil)
}
guard let data = jpegData(compressionQuality: compressionQuality) else { return nil }
try data.write(to: url)
return url
} catch {
print("-- Error: \(error)")
return nil
}
}
}
// load from path
extension UIImage {
convenience init?(fileURLWithPath url: URL, scale: CGFloat = 1.0) {
do {
let data = try Data(contentsOf: url)
self.init(data: data, scale: scale)
} catch {
print("-- Error: \(error)")
return nil
}
}
}
Usage
// save image (way 1)
let path = "photo/temp/album1/img.jpg"
guard let img = UIImage(named: "img"),
let url = img.save(at: .documentDirectory,
pathAndImageName: path) else { return }
print(url)
// get image from directory
guard let img2 = UIImage(fileURLWithPath: url) else { return }
// save image (way 2)
let tempDirectoryUrl = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(path)
guard let url2 = img2.save(at: tempDirectoryUrl) else { return }
print(url2)
Check results
open the iOS simulator directory
You should save image name with extension so your path should be like,
///var/mobile/Applications/BDB992FB-E378-4719-B7B7-E9A364EEE54B/Documents/tempImage.png
And second thing replace below line,
let result = pngImageData!.writeToFile(path, atomically: true)
with
let result = pngImageData!.writeToFile(path, atomically: false)
You need to set false as parameter of atomically.
atomically:
If true, the data is written to a backup file, and then—assuming no errors occur—the backup file is renamed to the name specified by path; otherwise, the data is written directly to path.
Hope this will help :)
Save image in local Xcode Documents directory
Pass in your image and the name you want to call it (you choose what you want fileName to be).
func saveImageLocally(image: UIImage, fileName: String) {
// Obtaining the Location of the Documents Directory
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
// Creating a URL to the name of your file
let url = documentsDirectory.appendingPathComponent(fileName)
if let data = image.pngData() {
do {
try data.write(to: url) // Writing an Image in the Documents Directory
} catch {
print("Unable to Write \(fileName) Image Data to Disk")
}
}
}
Read
Use the same fileName as when you saved it
func getImageFromName(fileName: String) {
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let url = documentsDirectory.appendingPathComponent(fileName)
if let imageData = try? Data(contentsOf: url) {
let image = UIImage(data: imageData) // HERE IS YOUR IMAGE! Do what you want with it!
} else {
print("Couldn't get image for \(fileName)")
}
}
Ashish's comment has a clue to the answer. If you read the docs on UIImage(contentsOfFile:) they say
path The path to the file. This path should include the filename
extension that identifies the type of the image data.
The imageNamed call is smart enough to try the .png and .jpg extensions, but the contentsOfFile call expects a full path including extension.
If you want to load image from server you can do like below
let url = URL(string: "http://live-wallpaper.net/iphone/img/app/i/p/iphone-4s-wallpapers-mobile-backgrounds-dark_2466f886de3472ef1fa968033f1da3e1_raw_1087fae1932cec8837695934b7eb1250_raw.jpg")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil
else { return }
DispatchQueue.main.async() { () -> Void in
let fileManager = FileManager.default
let paths = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("apple.jpg")
print(paths)
fileManager.createFile(atPath: paths as String, contents: data, attributes: nil)
}}.resume()
You can actually use PHPhotoLibrary to do that.
Here is the code for saving the image and fetching the image url.
extension UIImage {
func saveToPhotoLibrary(completion: #escaping (URL?) -> Void) {
var localeId: String?
PHPhotoLibrary.shared().performChanges({
let request = PHAssetChangeRequest.creationRequestForAsset(from: self)
localeId = request.placeholderForCreatedAsset?.localIdentifier
}) { (isSaved, error) in
guard isSaved else {
debugPrint(error?.localizedDescription)
completion(nil)
return
}
guard let localeId = localeId else {
completion(nil)
return
}
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let result = PHAsset.fetchAssets(withLocalIdentifiers: [localeId], options: fetchOptions)
guard let asset = result.firstObject else {
completion(nil)
return
}
getPHAssetURL(of: asset) { (phAssetUrl) in
completion(phAssetUrl)
}
}
}
static func getPHAssetURL(of asset: PHAsset, completionHandler : #escaping ((_ responseURL : URL?) -> Void))
{
let options: PHContentEditingInputRequestOptions = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = {(adjustmeta: PHAdjustmentData) -> Bool in
return true
}
asset.requestContentEditingInput(with: options, completionHandler: { (contentEditingInput, info) in
completionHandler(contentEditingInput!.fullSizeImageURL)
})
}
}
You have to create a directory in the Documents directory to be able to store a file.
Swift 5
func saveImage(image: UIImage) -> Bool{
guard let data = image.jpegData(compressionQuality: 1) ?? image.pngData() else {
return false
}
guard let directory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) as NSURL else {
return false
}
do{
try data.write(to: directory.appendingPathComponent("\(txtNom.text!).png")!)
print(directory)
print(data)
print("si se pudo")
return true
} catch {
print(error.localizedDescription)
return false
}
} // saveImage
I found the solution on StackOverFlow some time ago. I didn't remember the author
Assuming yourImage is UIImage()
let ciImage = yourImage!.ciImage
let context = CIContext()
let cgImage = context.createCGImage(ciImage!, from: ciImage!.extent)
let uiImage = UIImage(cgImage: cgImage!)
UIImageWriteToSavedPhotosAlbum(uiImage, self,
#selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil)
and this function
#objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if let error = error {
// we got back an error!
let ac = UIAlertController(title: "Save error", message: error.localizedDescription, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
} else {
let ac = UIAlertController(title: "Saved!", message: "Your altered image has been saved to your photos.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
}
I'm trying to display and save images with Swift. On first hit, it shows the remote image on imageview, on second hit it shows blank imageview instead of it should be local image which saved on first hit.
var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
var imagePath = paths.stringByAppendingPathComponent("images/\(id)/logo.jpg" )
var checkImage = NSFileManager.defaultManager()
if (checkImage.fileExistsAtPath(imagePath)) {
let getImage = UIImage(contentsOfFile: imagePath)
self.image?.image = getImage
} else {
dispatch_async(dispatch_get_main_queue()) {
let getImage = UIImage(data: NSData(contentsOfURL: NSURL(string: remoteImage)))
UIImageJPEGRepresentation(getImage, 100).writeToFile(imagePath, atomically: true)
self.image?.image = getImage
}
}
Edit: This one worked for me.
var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
var dirPath = paths.stringByAppendingPathComponent("images/\(id)" )
var imagePath = paths.stringByAppendingPathComponent("images/\(id)/logo.jpg" )
var checkImage = NSFileManager.defaultManager()
if (checkImage.fileExistsAtPath(imagePath)) {
let getImage = UIImage(contentsOfFile: imagePath)
self.image?.image = getImage
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
checkImage.createDirectoryAtPath(dirPath, withIntermediateDirectories: true, attributes: nil, error: nil)
let getImage = UIImage(data: NSData(contentsOfURL: NSURL(string: remoteImage)))
UIImageJPEGRepresentation(getImage, 100).writeToFile(imagePath, atomically: true)
dispatch_async(dispatch_get_main_queue()) {
self.image?.image = getImage
return
}
}
}
To answer your main question, you're calling the wrong UIImage initializer. You should be calling UIImage(contentsOfFile: imagePath) in swift 2 and UIImage(contentsOf: imagePath) in swift 3.
Additionally, it looks like you're trying to do your remote fetch in the background with dispatch_async (or DispatchQueue in swift 3), but you're passing it the main queue, so you're actually blocking the main/UI thread with that. You should dispatch it to one of the background queues instead and then dispatch back to the main queue when you actually set the image in your UI:
Swift 3 :
DispatchQueue.global(qos: DispatchQoS.background.qosClass).async {
do {
let data = try Data(contentsOf: URL(string: self.remoteImage)!)
let getImage = UIImage(data: data)
try UIImageJPEGRepresentation(getImage!, 100)?.write(to: imagePath)
DispatchQueue.main.async {
self.image?.image = getImage
return
}
}
catch {
return
}
}
Swift 2 :
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
let getImage = UIImage(data: NSData(contentsOfURL: NSURL(string: self.remoteImage)))
UIImageJPEGRepresentation(getImage, 100).writeToFile(imagePath, atomically: true)
dispatch_async(dispatch_get_main_queue()) {
self.image?.image = getImage
return
}
}
#Rob's answer re: fetching your remote image and saving it is really the best way to do this.
Your code that dispatches NSData(contentsOfURL:) (now known as Data(contentsOf:)) to the main queue. If you're going to use that synchronous method to request remote image, you should do this on a background queue.
Also, you are taking the NSData, converting it to a UIImage, and then converting it back to a NSData using UIImageJPEGRepresentation. Don't round-trip it though UIImageJPEGRepresentation as you will alter the original payload and will change the size of the asset. Just just confirm that the data contained an image, but then write that original NSData
Thus, in Swift 3, you probably want to do something like:
DispatchQueue.global().async {
do {
let data = try Data(contentsOf: URL(string: urlString)!)
if let image = UIImage(data: data) {
try data.write(to: fileURL)
DispatchQueue.main.async {
self.imageView?.image = image
}
}
} catch {
print(error)
}
}
Even better, you should use NSURLSession because you can better diagnose problems, it's cancelable, etc. (And don't use the deprecated NSURLConnection.) I'd also check the statusCode of the response. For example:
func requestImage(_ url: URL, fileURL: URL) {
let task = URLSession.shared.dataTask(with: url) { data, response, error in
// check for fundamental network issues (e.g. no internet, etc.)
guard let data = data, error == nil else {
print("dataTask error: \(error?.localizedDescription ?? "Unknown error")")
return
}
// make sure web server returned 200 status code (and not 404 for bad URL or whatever)
guard let httpResponse = response as? HTTPURLResponse, 200 ..< 300 ~= httpResponse.statusCode else {
print("Error; Text of response = \(String(data: data, encoding: .utf8) ?? "(Cannot display)")")
return
}
// save image and update UI
if let image = UIImage(data: data) {
do {
// add directory if it doesn't exist
let directory = fileURL.deletingLastPathComponent()
try? FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
// save file
try data.write(to: fileURL, options: .atomic)
} catch let fileError {
print(fileError)
}
DispatchQueue.main.async {
print("image = \(image)")
self.imageView?.image = image
}
}
}
task.resume()
}
Note, the just-in-time creation of the folder is only necessary if you haven't created it already. Personally, when I build the original path, I'd create the folder there rather than in the completion handler, but you can do this any way you want. Just make sure the folder exists before you write the file.
Regardless, hopefully this illustrates the main points, namely that you should save the original asset and that you should do this in the background.
For Swift 2 renditions, see previous revision of this answer.