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. plea
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
}
I have developed a small and straightforward CocoaPods library to work with Alamofire and Images.
CocoaPods is a great way of addressing your library dependencies needs. It is easy to install once, and easy to add and update dependencies to your projects.
The library is open source and can be found at https://github.com/gchiacchio/AlamoImage
It has great documentation with examples, so you will be enjoying it in minutes.
I have it working in a couple of project myself, including collection views and scrolling.
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) }
}
}
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)
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
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")