Lightweight and fast Swift library for image downloading
MapleBacon
Lightweight and fast Swift library for image downloading, caching and transformations.
Example
The folder Example
contains a sample projects for you to try.
Requirements
- Swift 5.1
- iOS 9.0+
- Xcode 10.2+
Installation
MapleBacon is available through CocoaPods. To install
it, simply add the following line to your Podfile:
pod "MapleBacon"
github "JanGorman/MapleBacon"
Usage
Combine & SwiftUI
Check the iOS13
branch of this project to try out Combine and SwiftUI support.
UIImageView
The most basic usage is via an extension on UIImageView
. You pass it a URL:
import MapleBacon
private var imageView: UIImageView!
func someFunc() {
let url = URL(string: "…")
imageView.setImage(with: url)
}
Just loading images is a little bit boring. Instead of just passing the URL you can also provide a placeholder, a progress handler that informs you about the download progress and a completion handler for any additional processing. Each of these parameters is optional, opt in to what you need:
func someFunc() {
let url = URL(string: "…")
imageView.setImage(with: url, placeholder: UIImage(named: "placeholder"), progress: { received, total in
// Report progress
}, completion: { [weak self] image in
// Do something else with the image
})
}
UIButton
MapleBacon also comes with an extension on UIButton
that works similar to the image view. The only additional parameter is the UIControlState
that the image is for:
import MapleBacon
@IBOutlet private var button: UIButton! {
didSet {
let normalUrl = URL(string: "…")
button.setImage(with: normalUrl, for: .normal)
let selectedUrl = URL(string: "…")
button.setImage(with: selectedUrl, for: .selected)
}
}
Image Transformers
MapleBacon allows you to apply transformations to images and have the results cached so that you app doesn't need to perform the same work over and over. To make your own transformer, create a class conforming to the ImageTransformer
protocol. A transform can be anything you like, let's create one that applies a Core Image sepia filter:
private class SepiaImageTransformer: ImageTransformer {
// The identifier is used as part of the cache key. Make sure it's something unique
let identifier = "com.schnaub.SepiaImageTransformer"
func transform(image: UIImage) -> UIImage? {
guard let filter = CIFilter(name: "CISepiaTone") else { return image }
let ciImage = CIImage(image: image)
filter.setValue(ciImage, forKey: kCIInputImageKey)
filter.setValue(0.5, forKey: kCIInputIntensityKey)
let context = CIContext()
guard let outputImage = filter.outputImage,
let cgImage = context.createCGImage(outputImage, from: outputImage.extent) else { return image }
// Return the transformed image which will be cached (or used by another transformer)
return UIImage(cgImage: cgImage)
}
}
You then pass this filter to MapleBacon in one of the convenience methods:
let url = URL(string: "…")
let transformer = SepiaImageTransformer()
imageView.setImage(with: url, transformer: transformer)
If you want to apply multiple transforms to an image, you can chain your transformers:
let chainedTransformer = SepiaImageTransformer()
.appending(transformer: DifferentTransformer())
.appending(transformer: AnotherTransformer())
Or if you prefer, using the custom >>>
operator:
let chainedTransformer = SepiaImageTransformer() >>> DifferentTransformer() >>> AnotherTransformer()
(Keep in mind that if you are using Core Image it might not be optimal to chain individual transformers but rather create one transformer that applies multiple CIFilter
s in one pass. See the Core Image Programming Guide.)
And just like the UIImageView
extension you can also pass in a progress and completion handler.
Caching
MapleBacon will cache your images both in memory and on disk. Disk storage is automatically pruned after a week (taking into account the last access date as well) but you can control the maximum cache time yourself too:
let oneDaySeconds: TimeInterval = 60 * 60 * 24
MapleBaconCache.default.maxCacheAgeSeconds = oneDaySeconds
MapleBacon handles clearing the in memory cache by itself should your app come under memory pressure.