I realized you can display images in widget like this stack overflow answer.
https://stackoverflow.com/a/64163384/13476728
However, I was wondering if this keeps calling the url every time when it refreshes through timelineprovider? if it does, how do i store the image through cache and display it so it doesnt call the url every time. (In this example "https://www.test.com")
Group {
let tempUrl = URL(string: "https://www.test.com")!
if let url = tempUrl, let imageData = try? Data(contentsOf: tempUrl),
let uiImage = UIImage(data: imageData) {
if(uiImage != nil){
Image(uiImage: uiImage)
.resizable()
} else{
black
}
}
}
In Swift 3, I am trying to capture an image from the internet, and have these lines of code:
var catPictureURL = NSURL(fileURLWithPath: "http://i.imgur.com/w5rkSIj.jpg")
var catPictureData = NSData(contentsOf: catPictureURL as URL) // nil
var catPicture = UIImage(data: catPictureData as! Data)
What am I doing wrong here?
There's a few things with your code as it stands:
You are using a lot of casting, which is not needed.
You are treating your URL as a local file URL, which is not the case.
You are never downloading the URL to be used by your image.
The first thing we are going to do is to declare your variable as let, as we are not going to modify it later.
let catPictureURL = URL(string: "http://i.imgur.com/w5rkSIj.jpg")! // We can force unwrap because we are 100% certain the constructor will not return nil in this case.
Then we need to download the contents of that URL. We can do this with the URLSession object. When the completion handler is called, we will have a UIImage downloaded from the web.
// Creating a session object with the default configuration.
// You can read more about it here https://developer.apple.com/reference/foundation/urlsessionconfiguration
let session = URLSession(configuration: .default)
// Define a download task. The download task will download the contents of the URL as a Data object and then you can do what you wish with that data.
let downloadPicTask = session.dataTask(with: catPictureURL) { (data, response, error) in
// The download has finished.
if let e = error {
print("Error downloading cat picture: \(e)")
} else {
// No errors found.
// It would be weird if we didn't have a response, so check for that too.
if let res = response as? HTTPURLResponse {
print("Downloaded cat picture with response code \(res.statusCode)")
if let imageData = data {
// Finally convert that Data into an image and do what you wish with it.
let image = UIImage(data: imageData)
// Do something with your image.
} else {
print("Couldn't get image: Image is nil")
}
} else {
print("Couldn't get response code for some reason")
}
}
}
Finally you need to call resume on the download task, otherwise your task will never start:
downloadPicTask.resume().
All this code may look a bit intimidating at first, but the URLSession APIs are block based so they can work asynchronously - If you block your UI thread for a few seconds, the OS will kill your app.
Your full code should look like this:
let catPictureURL = URL(string: "http://i.imgur.com/w5rkSIj.jpg")!
// Creating a session object with the default configuration.
// You can read more about it here https://developer.apple.com/reference/foundation/urlsessionconfiguration
let session = URLSession(configuration: .default)
// Define a download task. The download task will download the contents of the URL as a Data object and then you can do what you wish with that data.
let downloadPicTask = session.dataTask(with: catPictureURL) { (data, response, error) in
// The download has finished.
if let e = error {
print("Error downloading cat picture: \(e)")
} else {
// No errors found.
// It would be weird if we didn't have a response, so check for that too.
if let res = response as? HTTPURLResponse {
print("Downloaded cat picture with response code \(res.statusCode)")
if let imageData = data {
// Finally convert that Data into an image and do what you wish with it.
let image = UIImage(data: imageData)
// Do something with your image.
} else {
print("Couldn't get image: Image is nil")
}
} else {
print("Couldn't get response code for some reason")
}
}
}
downloadPicTask.resume()
let url = URL(string: "http://i.imgur.com/w5rkSIj.jpg")
let data = try? Data(contentsOf: url)
if let imageData = data {
let image = UIImage(data: imageData)
}
Swift
Good solution to extend native functionality by extensions
import UIKit
extension UIImage {
convenience init?(url: URL?) {
guard let url = url else { return nil }
do {
self.init(data: try Data(contentsOf: url))
} catch {
print("Cannot load image from url: \(url) with error: \(error)")
return nil
}
}
}
Usage
Convenience initializer is failable and accepts optional URL – approach is safe.
imageView.image = UIImage(url: URL(string: "some_url.png"))
You could also use Alamofire\AlmofireImage for that task:
https://github.com/Alamofire/AlamofireImage
The code should look something like that (Based on the first example on link above):
import AlamofireImage
Alamofire.request("http://i.imgur.com/w5rkSIj.jpg").responseImage { response in
if let catPicture = response.result.value {
print("image downloaded: \(image)")
}
}
While it is neat yet safe, you should consider if that worth the Pod overhead.
If you are going to use more images and would like to add also filter and transiations I would consider using AlamofireImage
Use this extension and download image faster.
extension UIImageView {
public func imageFromURL(urlString: String) {
let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
activityIndicator.frame = CGRect.init(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
activityIndicator.startAnimating()
if self.image == nil{
self.addSubview(activityIndicator)
}
URLSession.shared.dataTask(with: NSURL(string: urlString)! as URL, completionHandler: { (data, response, error) -> Void in
if error != nil {
print(error ?? "No Error")
return
}
DispatchQueue.main.async(execute: { () -> Void in
let image = UIImage(data: data!)
activityIndicator.removeFromSuperview()
self.image = image
})
}).resume()
}
}
Using Alamofire worked out for me on Swift 3:
Step 1:
Integrate using pods.
pod 'Alamofire', '~> 4.4'
pod 'AlamofireImage', '~> 3.3'
Step 2:
import AlamofireImage
import Alamofire
Step 3:
Alamofire.request("https://httpbin.org/image/png").responseImage { response in
if let image = response.result.value {
print("image downloaded: \(image)")
self.myImageview.image = image
}
}
The easiest way according to me will be using SDWebImage
Add this to your pod file
pod 'SDWebImage', '~> 4.0'
Run pod install
Now import SDWebImage
import SDWebImage
Now for setting image from url
imageView.sd_setImage(with: URL(string: "http://www.domain/path/to/image.jpg"), placeholderImage: UIImage(named: "placeholder.png"))
It will show placeholder image but when image is downloaded it will show the image from url .Your app will never crash
This are the main feature of SDWebImage
Categories for UIImageView, UIButton, MKAnnotationView adding web image and cache management
An asynchronous image downloader
An asynchronous memory + disk image caching with automatic cache expiration handling
A background image decompression
A guarantee that the same URL won't be downloaded several times
A guarantee that bogus URLs won't be retried again and again
A guarantee that main thread will never be blocked
Performances!
Use GCD and ARC
To know more https://github.com/rs/SDWebImage
Use extension for UIImageView to Load URL Images.
let imageCache = NSCache<NSString, UIImage>()
extension UIImageView {
func imageURLLoad(url: URL) {
DispatchQueue.global().async { [weak self] in
func setImage(image:UIImage?) {
DispatchQueue.main.async {
self?.image = image
}
}
let urlToString = url.absoluteString as NSString
if let cachedImage = imageCache.object(forKey: urlToString) {
setImage(image: cachedImage)
} else if let data = try? Data(contentsOf: url), let image = UIImage(data: data) {
DispatchQueue.main.async {
imageCache.setObject(image, forKey: urlToString)
setImage(image: image)
}
}else {
setImage(image: nil)
}
}
}
}
We are able to fetch image directly without using Third Party SDK like 'AlamofireImage', 'Kingfisher' and 'SDWebImage'
Swift 5
DispatchQueue.global(qos: .background).async {
do{
let data = try Data.init(contentsOf: URL.init(string:"url")!)
DispatchQueue.main.async {
let image: UIImage? = UIImage(data: data)
yourImageView.image = image
}
}
catch let errorLog {
debugPrint(errorLog.localizedDescription)
}
}
let url = ("https://firebasestorage.googleapis.com/v0/b/qualityaudit-678a4.appspot.com/o/profile_images%2FBFA28EDD-9E15-4CC3-9AF8-496B91E74A11.png?alt=media&token=b4518b07-2147-48e5-93fb-3de2b768412d")
self.myactivityindecator.startAnimating()
let urlString = url
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url)
{
(data, response, error) in
if error != nil {
print("Failed fetching image:", error!)
return
}
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
print("error")
return
}
DispatchQueue.main.async {
let image = UIImage(data: data!)
let myimageview = UIImageView(image: image)
print(myimageview)
self.imgdata.image = myimageview.image
self.myactivityindecator.stopanimating()
}
}.resume()
I use AlamofireImage it works fine for me for Loading url within ImageView, which also has Placeholder option.
func setImage (){
let image = “https : //i.imgur.com/w5rkSIj.jpg”
if let url = URL (string: image)
{
//Placeholder Image which was in your Local(Assets)
let image = UIImage (named: “PlacehoderImageName”)
imageViewName.af_setImage (withURL: url, placeholderImage: image)
}
}
Note:- Dont forget to Add AlamofireImage in your Pod file as well as in Import Statment
Say Example,
pod 'AlamofireImage' within Your PodFile and in ViewController import AlamofireImage
I am developing Restaurant app.
There are 340 foods data.
I am getting this data from backend that developed with Laravel.
App is working well in online.
But, although network is turned off, All foods data should be displayed in app.
So, I tried to save foods data to local.
It is good to save text data to local(exactly, UserDefaults and FileSystem).
But, when I try to save images to local from urls, It occur error and don't save to local exactly.
Have you ever seen such problems?
If yes, I appreciate your help.
Thanks
I don't know exactly what error you faced, but I think the answer to the link can help you.
How do I make JSON data persistent for offline use (Swift 4)
Additionally, image data would be good to be cached.
If you communicate based on URLSession, you can process caching as below.
Saving an Image to a Cache
Cache.imageCache.setObject(image, forKey: url.absoluteString as NSString)
Bring up cached images
let cacheImage = Cache.imageCache.object(forKey: url.absoluteString as NSString)
Code
class Cache {
static let imageCache = NSCache<NSString, UIImage>()
}
extension UIImageView {
func imageDownload(url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit) {
if let cacheImage = Cache.imageCache.object(forKey: url.absoluteString as NSString) {
DispatchQueue.main.async() { [weak self] in
self?.contentMode = mode
self?.image = cacheImage
}
}
else {
var request = URLRequest(url: url)
request.httpMethod = "GET"
URLSession.shared.dataTask(with: request) { 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,
let image = UIImage(data: data)
else {
print("Download image fail : \(url)")
return
}
DispatchQueue.main.async() { [weak self] in
print("Download image success \(url)")
Cache.imageCache.setObject(image, forKey: url.absoluteString as NSString)
self?.contentMode = mode
self?.image = image
}
}.resume()
}
}
}
To make caching more convenient, use a library called Kingfisher.
Kingfisher
You need to manage lazy loadings, you can use SDWebImages instead of manage it manually
SDWebImages will automatically manage your images caches and will also load them without internet here is a simple usage of it
add pod in podfile
pod 'SDWebImage'
usagae:
import SDWebImage
imageView.sd_setImage(with: URL(string: "http://www.example.com/path/to/image.jpg"), placeholderImage: UIImage(named: "placeholder.png"))
I need to display the background image of a button by giving the image source from an external URL instead of downloading the image. Is there a possible way to do this in swift.
You can use SDWebImage POD.
yourBtn.sd_setImage(with: <#T##URL?#>, for: <#T##UIControl.State#>, completed: <#T##SDExternalCompletionBlock?##SDExternalCompletionBlock?##(UIImage?, Error?, SDImageCacheType, URL?) -> Void#>)
First you need to get the image data from external URL and then use the image
if let url = URL(string: "YOUR-IMAGE-URL-HERE") {
do{
let data = try Data(contentsOf: url)
self.imageVar = UIImage(data: data)
if let myImage: UIImage = self.imageVar {
YOUR-BUTTON-NAME.setImage(myImage, for: .normal)
}
}catch {
print("error")
}
}
I am trying to figure out how to load an image via it's url (think facebook profile picture) in a cocos2d game. Can someone help me? I'm using swift but have no idea how to get this image displayed on the UI. Here is what I have so far...
if let currentUserName = PFUser.currentUser()!["profilepic"] as? String {
if let url = NSURL(string: currentUserName) {
if let data = NSData(contentsOfURL: url){
}
}
if let profilePic = PFUser.currentUser()!["profilepic"] as? String {
if let url = NSURL(string: profilePic) {
if let data = NSData(contentsOfURL: url){
imgView.image = UIImage(data: data!) //where imgView is your UIImageView
}
}
}