So my app only displays images in a CollectionView and it crashes because of memory issues. This is the memory graph
This is the sample project you can check. ImageTest
I've tried this same project with Kingfisher Library and AlamofireImage Library and it crashes on both.
It seems likely that the problem is caused by your images being too large. I see two solutions.
Try using PINRemoteImage. It's in ObjC but you can bridge to Swift. This framework allows you to set limits on cache size, which should prevent your memory from being gobbled up.
However, this might not help because you could end up not having all your images.
Because, as you noted, scaling the images one by one is manual (and therefore tedious), I suggest scaling on the client-end.
To do this, you would probably end up writing your own caching code. I've done this before though, and I can attest that it is actually quite simple to get something that meets your needs. For example, when I had to cache images, I ended up creating a dictionary that stores images with url keys. Before you store the images in the dictionary, you scale them down.
As requested, here is some sample code to help you out. This isn't the entire code, but it is a very solid base.
Downloading the image
Use Alamofire
to download the image from a URL:
Alamofire.request(.GET, "https://robohash.org/123.png").response { (request, response, data, error) in
self.myImageView.image = UIImage(data: data, scale:1)
}
Scaling the image
Use the code from this answer on SO. You should scale to the size that you need the image and no more.
Storing the image
Let's back up a bit. I would have all of this code managed by a class, ImageManager
, or something like that.
ImageManager
should have:
var delegate: ImageManagerDelegate? // the delegate; more detail below
private(set) var images: [URL: UIImage] = [:] // the cache
func getImage(from url: URL) // the entry point to the class; calls the delegate immediately if the image is already cached, else calls `downloadImage(url: url)`
private func downloadImage(url: URL) // actually downloads the image; calls `cacheImage(url: url, image: downloadedImage)`
private func cacheImage(url: URL, image: UIImage) // caches the image in `images` with `url` as the key, and notifies `delegate` that an image has been cached with the specified url.
ImageManager
should also implement ImageManagerDelegate
:
protocol ImageManagerDelegate {
func imageManager(_ manager: ImageManager, didGet image: UIImage, from url: URL)
}