56

I need to get a UIImage only instead of loading a normal UIImageView with Kingfisher library

To realize it I implemented a workaround with UIImageView:

let imageView = UIImageView()

imageView.kf_setImageWithURL(NSURL(string: cpa.imageName)!, placeholderImage: nil,
        optionsInfo: [.Transition(ImageTransition.Fade(1))],
        progressBlock: { receivedSize, totalSize in
            print("\(receivedSize)/\(totalSize)")
        },
        completionHandler: { image, error, cacheType, imageURL in
            anView!.image = image //anView IS NOT an UIImageView
            anView!.frame.size = CGSize(width: 15.0, height: 15.0)
            print("Finished")
    })

This code works perfectly, but I would like to do it in a cleaner way. Is there a method in this library to get an UIImage only? Async and cached

Patonz
  • 884
  • 1
  • 6
  • 17

9 Answers9

81

You could use the retrieveImage(with:options:progressBlock: completionHandler:) method of KingfisherManager for this.

Maybe something like this:

KingfisherManager.shared.retrieveImage(with: url, options: nil, progressBlock: nil, completionHandler: { image, error, cacheType, imageURL in
    print(image)
})
Jakub Truhlář
  • 20,070
  • 9
  • 74
  • 84
onevcat
  • 4,591
  • 1
  • 25
  • 31
47

This is latest syntax to download image in kingFisher 5 (Tested in swift 4.2)

func downloadImage(`with` urlString : String){
    guard let url = URL.init(string: urlString) else {
        return
    }
    let resource = ImageResource(downloadURL: url)

    KingfisherManager.shared.retrieveImage(with: resource, options: nil, progressBlock: nil) { result in
        switch result {
        case .success(let value):
            print("Image: \(value.image). Got from: \(value.cacheType)")
        case .failure(let error):
            print("Error: \(error)")
        }
    }
}

How to call above function

self.downloadImage(with: imageURL) //replace with your image url
Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
  • 1
    resource is a URL("url-string") object, so for anyone coming from another language it is not clear. Also, you could remove parameters where you send nil, and you could remove the completion hanlder when you don't care about the image don't loading. – sgelves May 19 '19 at 14:53
12

With the new Swift 3 version you can use ImageDownloader :

ImageDownloader.default.downloadImage(with: url, options: [], progressBlock: nil) {
    (image, error, url, data) in
    print("Downloaded Image: \(image)")
}

ImageDownloader is a part of Kingfisher so don't forget to import Kingfisher.

Argus
  • 2,241
  • 1
  • 22
  • 27
Paweł
  • 1,201
  • 1
  • 14
  • 27
  • 5
    This would not leverage the cache as per this [line](https://github.com/onevcat/Kingfisher/blob/743e3f2a54408de212d8ec74a5c91747b6a26f7e/Sources/ImageDownloader.swift#L288) `cachePolicy: .reloadIgnoringLocalCacheData` which is the point of using Kinfisher over any other simpler method – Jaime Agudo Dec 31 '16 at 12:52
9

Swift 5:

I will complete on @Hardik Thakkar answer to add a change so that you can return the image using a closure may that helps somebody:

func downloadImage(with urlString : String , imageCompletionHandler: @escaping (UIImage?) -> Void){
        guard let url = URL.init(string: urlString) else {
            return  imageCompletionHandler(nil)
        }
        let resource = ImageResource(downloadURL: url)
        
        KingfisherManager.shared.retrieveImage(with: resource, options: nil, progressBlock: nil) { result in
            switch result {
            case .success(let value):
                imageCompletionHandler(value.image)
            case .failure:
                imageCompletionHandler(nil)
            }
        }
    }

How to call:

 downloadImage(with :yourUrl){image in
     guard let image  = image else { return}
      // do what you need with the returned image.
 }
Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
Mina Farid
  • 5,041
  • 4
  • 39
  • 46
6

Another way in Kingfisher 5:

KingfisherManager.shared.retrieveImage(with: url) { result in
    let image = try? result.get().image
    if let image = image {
        ...
    }
}
aneurinc
  • 1,238
  • 12
  • 20
6

Swift 5 Kingfisher 5

This code is 100% working

YourImageView.kf.setImage(with: URL(string: imagePath), placeholder: nil, options: nil, progressBlock: nil, completionHandler: { result in
switch result {
    case .success(let value):
                print("Image: \(value.image). Got from: \(value.cacheType)")
    case .failure(let error):
                print("Error: \(error)")
    }
})

//OR
let resource = ImageResource(downloadURL: picUrl!)
KingfisherManager.shared.retrieveImage(with: resource, options: nil, progressBlock: nil) { result in
    switch result {
        case .success(let value):
        print("Image: \(value.image). Got from: \(value.cacheType)")
        imageProfile = value.image
        case .failure(let error):
            print("Error: \(error)")
        }
    }
Shakeel Ahmed
  • 5,361
  • 1
  • 43
  • 34
5

In Kingfisher 5

imageView.kf.setImage(with: url) { result in
   switch result {
   case .success(let value):
       print("Image: \(value.image). Got from: \(value.cacheType)")
   case .failure(let error):
       print("Error: \(error)")
   }
 } 

see more: https://github.com/onevcat/Kingfisher/wiki/Kingfisher-5.0-Migration-Guide

Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
Quyen Anh Nguyen
  • 1,204
  • 13
  • 21
0

If you want to custom UILabel instated of UIImageView from api call.

import Kingfisher
func getImage(imageUrl: String,title:String?=nil){

        let someTitle = UILabel()
        view.addSubview(someTitle)
        someTitle.text = title
        someTitle.isHidden = true
       
        someTitle.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        someTitle.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
        someTitle.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        someTitle.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [self] in
            let url = URL(string: imageUrl )
            yourImage.kf.setImage(
                with: url,
                placeholder:  (someTitle as? Placeholder),
                options: [
                    .loadDiskFileSynchronously,
                    .cacheOriginalImage,
                    .transition(.fade(0.25))
                ],
                completionHandler: { result in
                    // Done
                    switch result {
                    case .success(let value):
                         self.yourImage.image = value.image
                    case .failure(let error):
                        someTitle.isHidden = false
                    }
                }
            )
                        
        }
    }

Just call the function in your Controller


getImage(imageUrl: you_url, title: your_name)

imran
  • 1
  • 5
0

If you want to have a custom UIImage and UIImageView

let url = URL(string: "https://iosacademy.io/assets/images/brand/icon.jpg")

override func viewDidLoad() {
    super.viewDidLoad()
    addPicture()
    
}

private func addPicture() {
    let containerView = UIView()
    //let myImage = UIImage(named: "Old Scroll Lengmei") // to add UIImage  by code
    let myImage = UIImage()
    let myImageView = UIImageView() // to add UIImageView by code
    let label = UILabel() // to add Label by code
    
    myImageView.kf.setImage(with: url)