Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to load image in swift using Alamofire

I have a collection view controller, which load image Async by URL. (Something like Instegram) I am looking for the best way to implement the part of the loading image. please tell me what do you think

First way - without any external library:

   let downloadQueue = dispatch_queue_create("com.pro.asyncImages",nil)
    dispatch_async(downloadQueue){

        var data = NSData(contentsOfURL: NSURL(string: pictureUrl!)!)

        var image: UIImage?
        if (data != nil){
            image = UIImage(data: data!)
        }
        dispatch_async(dispatch_get_main_queue()){
            uiImageView.image = image
        }
    }

Second way - using Alamofire (the request belong to Alamofire)

if let  mediaUrl = info.mediaUrl {
        request(.GET,mediaUrl).response(){
            (_, _, data, _) in
            let image = UIImage(data: data! as NSData)
            imageView.image = image
        }
    }

And lastly, I read that AFNetworking, is doing a great job in loading url async to urlImage, Which this is what I want to do.

So is AFNetworking is better for this task? (then Alamofire) and if not, I did not understand how to add AFNetworking to my swift project, beside adding the #import “AFNetworking.h” which files do I need to add?

please explain which method is the best, my needs are performance, accusation, caching. the view collection controller acts like Instegram and is loading images, while scrolling down. I hope I was clear enough about what I need, thank you

like image 858
user3728728 Avatar asked Feb 20 '15 19:02

user3728728


Video Answer


8 Answers

As authors mention in Alamofire README.md:

When should I use AFNetworking?

  • UIKit extensions, such as asynchronously loading images to UIImageView

So answer to your question :

So is AFNetworking is better for this task?

Yes!

But if still want to use vanilla Alamofire project, you can fetch image this way:

   Alamofire.request(.GET, "https://robohash.org/123.png").response { (request, response, data, error) in
        self.myImageView.image = UIImage(data: data, scale:1)
    }

P.S.

But if you just want to load image (of course async) - you don't need to use Alamofire or AFNetworking at all. Just add this small extension in your code:

extension UIImageView {
    public func imageFromUrl(urlString: String) {
        if let url = NSURL(string: urlString) {
            let request = NSURLRequest(URL: url)
            NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
                (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
                self.image = UIImage(data: data)
            }
        }
    }
}

And use it:

myImageView.imageFromUrl("https://robohash.org/123.png")
like image 129
skywinder Avatar answered Oct 01 '22 17:10

skywinder


I created a Swift version of UIImageView+AFNetworking here : Github.
You don't have to use AFNetworking (and a bridging header) or Alamofire in your project. Just add the file to your project and use it.


Example usage:

myImageView.setImageWithUrl(imageUrl, placeHolderImage: somePlaceHolderImage)
like image 33
namanhams Avatar answered Oct 01 '22 17:10

namanhams


Taken from Alamofire/README.md

"In order to keep Alamofire focused specifically on core networking implementations, additional component libraries have been created by the Alamofire Software Foundation to bring additional functionality to the Alamofire ecosystem.

AlamofireImage - An image library including image response serializers, UIImage and UIImageView extensions, custom image filters, an auto-purging in-memory cache and a priority-based image downloading system."

https://github.com/Alamofire/AlamofireImage

like image 45
james.ff Avatar answered Oct 01 '22 19:10

james.ff


In swift 5 & Alamofire 5,You can use like bellow..

  AF.request( "https://robohash.org/123.png",method: .get).response{ response in

   switch response.result {
    case .success(let responseData):
        self.myImageView.image = UIImage(data: responseData!, scale:1)

    case .failure(let error):
        print("error--->",error)
    }
}
like image 28
Enamul Haque Avatar answered Oct 01 '22 17:10

Enamul Haque


If you want to use AFNetworking's UImageView framework, you have to do #import "UIImageView+AFNetworking.h" in your bridge-header file.

AFNetworking has a shared cache, so you won’t need to manually cache or cancel your requests. The setImageWithURL from AFNetworking can easily convert a URL to an image in ImageView.

Sample code using UIImage+AFNetworking:

cell.imageView.setImageWithURL(NSURL(string:imageSource), placeholderImage: UIImage(named:"placeholder"))

If you are using Alamofire, you have to manually convert NSData to UIImage. For Alamofire, you can create a NSCache() object to cache your images. The performance of both library should be similar. You can use Alamofire for your server API calls and then use AFNetworking to display images asynchronously.

Sample code using Alamofire for image cache:

let imageCache = NSCache()

 if let image = self.imageCache.objectForKey(imageURL) as? UIImage {
    cell.imageView.image = image
  } else {
    // 3
    cell.imageView.image = nil

    // 4
    cell.request = Alamofire.request(.GET, imageURL).validate(contentType: ["image/*"]).responseImage() {
      (request, _, image, error) in
      if error == nil && image != nil {
        // 5
        self.imageCache.setObject(image!, forKey: request.URLString)

        // 6
        if request.URLString == cell.request?.request.URLString {
          cell.imageView.image = image
        }
      } else {
        /*
        If the cell went off-screen before the image was downloaded, we cancel it and
        an NSURLErrorDomain (-999: cancelled) is returned. This is a normal behavior.
        */
      }
    }
  } 

You can read this tutorial for more detail about using Alamofire.

like image 21
ztan Avatar answered Oct 01 '22 17:10

ztan


Actually there are multiple ways to load your image from URL using Alamofire. and this is a way that i've developed and i'm using it already in one of my Swift projects. This way i'm loading the images Asyncrounsly and display them into UITableView and from performance wise it's fine and there is no blocking while scrolling UITableView because it's care about cashing the images loaded.

First you have to create a GET request using Alamofire to download the image, and you have to use Request+AlamofireImage from AlamofireImage Library so you have to

import AlamofireImage

And then in

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

}

you have to call your image download request like this:

         //Download image
        // We should perform this in a background thread
        Alamofire.request(.GET, deshItem.dish_imageUrl!)
            .responseImage { response in
                debugPrint(response)

                print(response.request)
                print(response.response)
                debugPrint(response.result)

                if let image = response.result.value {
                    print("image downloaded: \(image)")

                    // Store the commit date in to our cache
                    self.ImageCache[dishName!] = image

                    // Update the cell
                    dispatch_async(dispatch_get_main_queue(), {
                        if let cellToUpdate = tableView.cellForRowAtIndexPath(indexPath) {
                                let dishImageView:UIImageView = cellToUpdate.viewWithTag(104) as! UIImageView
                                dishImageView.image = image

                        }
                    })

                }
        }

For Image Caching i've created a dictionary that will contain image for every cell or item(String), So this way of caching images will avoid the locking that appear while scrolling.

Complete Sample code:

import AlamofireImage

class MainFeedTableViewController: UITableViewController, FloatRatingViewDelegate {

var ImageCache = [String:UIImage]()


override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("MainFeedCellID", forIndexPath: indexPath)

    // Configure the cell...

    let dishName = deshItem.dish_name

    //This is a workaround to cash the image and improve the performance while user scrolling UITableView.
    // If this image is already cached, don't re-download
    if let dishImage = ImageCache[dishName!] {
                let dishImageView:UIImageView = cell.viewWithTag(104) as! UIImageView
                dishImageView.image = dishImage
    }
    else {
        //Download image
        // We should perform this in a background thread
        Alamofire.request(.GET, deshItem.dish_imageUrl!)
            .responseImage { response in
                debugPrint(response)

                print(response.request)
                print(response.response)
                debugPrint(response.result)

                if let image = response.result.value {
                    print("image downloaded: \(image)")

                    // Store the commit date in to our cache
                    self.ImageCache[dishName!] = image

                    // Update the cell
                    dispatch_async(dispatch_get_main_queue(), {
                        if let cellToUpdate = tableView.cellForRowAtIndexPath(indexPath) {
                                let dishImageView:UIImageView = cellToUpdate.viewWithTag(104) as! UIImageView
                                dishImageView.image = image

                        }
                    })

                }
        }

    }



    return cell
}
like image 28
smapps Avatar answered Oct 01 '22 19:10

smapps


Here's an approach using RxAlamofire:

import Alamofire
import RxAlamofire

extension UIImageView {
    public func imageFromUrl(urlString: String) {
        requestData(.GET, urlString)
            .observeOn(MainScheduler.instance)
            .subscribeNext { self.image = UIImage(data: $0.1) }
    }
}
like image 45
Lukas Batteau Avatar answered Oct 01 '22 19:10

Lukas Batteau


You can download image by using responseData(queue:completionHandler:)

SWIFT 4

func downloadImages(imageURL: String) {

    Alamofire.request(imageURL, method: .get)
        .validate()
        .responseData(completionHandler: { (responseData) in
            self.yourImageVIew.image = UIImage(data: responseData.data!) 
            DispatchQueue.main.async {
                // Refresh you views
            }
        })
}
like image 25
Chathuranga Silva Avatar answered Oct 01 '22 18:10

Chathuranga Silva