I have images in my collectionViewCell's that are fetched and parsed via NSURLRequest, how do I cache these images so they don't have to start a new request with every single appearance/disappearance of the view?
here is my code that fetches the images:
class funnyPicture: NSObject {
var pfPicture : PFObject
var coverImage : UIImage!
init(pfPicture: PFObject) {
self.pfPicture = pfPicture
}
func fetchCoverImage(completion: (image: UIImage?, error: NSError?) -> Void) {
let urlString = self.pfPicture["funnyPictures"] as! String
let url = NSURL(string: urlString)
let request = NSURLRequest(URL: url!)
let queue = dispatch_get_main_queue()
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { (response: NSURLResponse?, data: NSData?, error: NSError?) in
if error == nil {
self.coverImage = UIImage(data: data!)
completion(image: self.coverImage, error: nil)
} else {
completion(image: nil, error: error)
}
}
}
}
and here is my collectionView code that parse the images to the collectionViewCell's:
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! MyCollectionViewCell
// Configure the cell
let book = self.books[indexPath.row]
let coverImage = book.coverImage
if coverImage == nil {
book.fetchCoverImage({ (image, error) -> Void in
if self.collectionView != nil {
collectionView.reloadItemsAtIndexPaths([indexPath])
}
})
} else {
dispatch_async(dispatch_get_main_queue()){
let imageView = cell.imageView
imageView.image = book.coverImage
}
};
if book.coverImage == nil {
cell.imageView.userInteractionEnabled = false
cell.userInteractionEnabled = false
}else {
cell.imageView.userInteractionEnabled = true
cell.userInteractionEnabled = true
}
return cell
}
While I've received references to third party frameworks, I haven't received any answer on how to implement them with the code I have provided in the question, or even an answer using apples already implemented caching mechanism.. The reason I put the code in the question was for use in an answer.. Thank you.
Here is an example for your collection view cell:
import UIKit
let imageCache = NSCache<AnyObject, AnyObject>.sharedInstance
class myCell: UICollectionViewCell {
@IBOutlet public weak var myImageView: UIImageView?
private var imageUrlString: String?
private var downloadTask: URLSessionDownloadTask?
public var imageURL: URL? {
didSet {
self.downloadItemImageForSearchResult(imageURL: imageURL)
}
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
public func downloadItemImageForSearchResult(imageURL: URL?) {
if let urlOfImage = imageURL {
if let cachedImage = imageCache.object(forKey: urlOfImage.absoluteString as NSString){
self.myImageView!.image = cachedImage as? UIImage
} else {
let session = URLSession.shared
self.downloadTask = session.downloadTask(
with: urlOfImage as URL, completionHandler: { [weak self] url, response, error in
if error == nil, let url = url, let data = NSData(contentsOf: url), let image = UIImage(data: data as Data) {
DispatchQueue.main.async() {
let imageToCache = image
if let strongSelf = self, let imageView = strongSelf.myImageView {
imageView.image = imageToCache
imageCache.setObject(imageToCache, forKey: urlOfImage.absoluteString as NSString , cost: 1)
}
}
} else {
//print("ERROR \(error?.localizedDescription)")
}
})
self.downloadTask!.resume()
}
}
}
override public func prepareForReuse() {
self.downloadTask?.cancel()
myImageView?.image = UIImage(named: "ImagePlaceholder")
}
deinit {
self.downloadTask?.cancel()
myImageView?.image = nil
}
}
Don't forget to make an extension for NSCache Like this:
import Foundation
extension NSCache {
class var sharedInstance: NSCache<NSString, AnyObject> {
let cache = NSCache<NSString, AnyObject>()
return cache
}
}
Use NSCache and NSOperationQueue to manage your image loading. There's a good post outlining the technique at https://stackoverflow.com/a/12721899/5271191 (It's Objective-C, but the technique is the same for Swift.)
I highly recommend you to use a clean in place replacement/extension for UIImageView, that will manage caching of the image all transparently to you and avoid unwanted complexity of maintaining operation queues, etc.
If in memory caching suffices your needs - check this out-
https://github.com/nicklockwood/AsyncImageView
If you want persistent caching, then this one will do-
https://github.com/rs/SDWebImage
HTH.
I have images in my collectionViewCell's that are fetched and parsed via NSURLRequest, how do I cache these images so they don't have to start a new request with every single appearance/disappearance of the view?
The URL loading system already provides a cache. Take a look at the docs for NSURLCache. If the resources you need aren't already being sufficiently cached, you probably only need to adjust the disk space allocated to the URL cache for your app.
You should also take a look at the headers (cache-control, expires, etc.) that come back with your resources to make sure that they're not preventing caching. Here's a short tutorial on cache-related headers.
You should use a specialized framework for that. I would not recommend using SDWebImage, it is very outdated and is not stable.
Take a look at those two libraries that are up to date with iOS platform:
- DFImageManager - advanced framework written in Objective-C but featuring nullability annotations (works great with Swift). Here's a list of things that make it better, than SDWebImage. Disclosure: it's written by me, opinion might be biased.
- Kingfisher - lightweight library written in Swift. Similar to SDWebImage, but has much less features that SDWebImage and DFImageManager.
I have created a library using swift 2 to do the request for image and cache it. it's very simple just give it a try.
https://github.com/georgehadly/GHImageCaching
all you can do is something like this ,
viewImg.getCachedImage("geo", URI: NSURL(string: "https://s-media-cache-ak0.pinimg.com/236x/8e/5a/98/8e5a98795dc2c5322cac97343a6cad6d.jpg")!) { (done) -> Void in
if(done){
// your extra
}
}
in case you want to delete all cached images
UIImageView.deleteAllCaching()
来源:https://stackoverflow.com/questions/32577207/caching-images-in-collectionviewcell-in-swift