Swiftpack.co - Package - JanGorman/MapleBacon


CI codecov.io Version License Platform Carthage compatible SPM


MapleBacon is a lightweight and fast Swift library for downloading and caching images.


The folder Example contains a sample projects for you to try.


  • Swift 5.1
  • iOS 10.0+
  • Xcode 10.2+


MapleBacon is available through CocoaPods. To install add it to your Podfile:

pod "MapleBacon"

Carthage / punic:

github "JanGorman/MapleBacon"

and Swift Package Manager.



The most basic usage is via an extension on UIImageView. You pass it URL:

import MapleBacon

private var imageView: UIImageView!

func someFunc() {
  let url = URL(string: "…")
  imageView.setImage(with: url)

If you want to add a placeholder while the image is downloading you specify that like this:

func someFunc() {
  let url = URL(string: "…")
  imageView.setImage(with: url, placeholder: UIImage(named: "placeholder"))

If your backend returns images that are not optimised for display, it's good practice to downsample them. MapleBacon comes with support for downsampling via displayOptions:

func someFunc() {
  let url = URL(string: "…")
  imageView.setImage(with: url, displayOptions: .downsampled)

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 ImageTransforming protocol. A transform can be anything you like, let's create one that applies a Core Image sepia filter:

private class SepiaImageTransformer: ImageTransforming {

  // 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? {
    let filter = CIFilter(name: "CISepiaTone")!

    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 CIFilters in one pass. See the Core Image Programming Guide.)


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
MapleBacon.default.maxCacheAgeSeconds = oneDaySeconds


On iOS13 and above, you can use Combine to fetch images from MapleBacon

MapleBacon.shared.image(with: url)
  .receive(on: DispatchQueue.main) // Dispatch to the right queue if updating the UI
  .sink(receiveValue: { image in
    // Do something with your image
  .store(in: &subscriptions) // Hold on to and dispose your subscriptions

Migrating from 5.x

There is a small migration guide in the wiki when moving from the 5.x branch to 6.x


MapleBacon is available under the MIT license. See the LICENSE file for more info.


Stars: 271


Used By

Total: 0


Tune-up - 2020-03-15 15:20:51

  • Tweaking V6

- 2020-03-01 14:14:44

  • Spring cleaning release

- 2020-03-01 14:09:24

  • Spring cleaning release

- 2020-02-10 12:44:44

  • Prune disk cache on both UIApplication.willTerminateNotification and UIApplication.didEnterBackgroundNotification

- 2020-01-10 14:11:32

  • Enable build for distribution

SPM Support - 2019-11-26 20:03:35

  • Support for Swift Package Manager

- 2019-11-07 08:28:18

  • Fix an issue with xcodebuild that prevented installing as Carthage or CocoaPod dependency

- 2019-11-05 06:17:04

CrypotKit - 2019-11-04 20:50:50

  • Use CryptoKit to hash the cache key if available

Combine - 2019-11-03 17:10:37

  • Adds support for Combine

- 2019-08-26 19:04:20

  • A little bit of maintenance

- 2019-07-22 10:57:09

  • Make dispatching to the main thread optional. Only needed when no options are passed and a transformer is passed.

- 2019-07-22 09:52:37

  • Pass through the UUID returned by the download in the UIImageViewExtension

- 2019-07-22 09:45:00

  • Pass through the UUID returned by the download in the UIImageViewExtension

Cancellable downloads - 2019-07-19 09:51:32

  • Downloads will now return an identifier token that can be used to cancel a running download

`Data` access - 2019-07-18 18:35:04

  • Expose the underlying Data. You can now ask the cache class for Data instead of a UIImage and the MapleBacon singleton that either fetches over the air or from cache also exposes direct access to Data
  • Rename Cache to MapleBaconCache to make it less generic when used in a project

- 2019-06-16 12:08:54

  • Fixes bug that was using the wrong cache key when pushing an image retrieved from disk back to memory

Image Scaling - 2019-05-08 08:55:02

  • Introduces a new displayOptions parameter that can be passed to the setImage extension on UIImageView
    • .scaled: This will scale the image to the image view's frame before setting the image. This significantly cuts memory use. Because this is done asynchronously images are set a little bit slower than without the parameter. It's a tradeoff you need to consider
    • .withTransition: Instead of just setting the image, this will set the image with a .transitionCrossDissolve animation
    • The two options work together nicely

Swift 5 - 2019-04-02 07:28:37

  • Update project to Swift 5

- 2019-01-08 12:46:18

  • Wraps the download in a background task to fix iOS 12 issue (See #57). Thanks @Igor-Palaguta

Swift 4.2 - 2018-09-23 14:57:55

- 2018-05-31 15:33:41

  • Adds a preWarmCache(for: URL) method to the shared instance.

- 2018-05-30 08:40:17

  • Add URL check to UIButton too (5.1.6 added this for UIImageView)

- 2018-05-29 14:57:42

- 2018-05-11 11:24:58

  • Don't embed Swift standard library

Custom chaining - 2018-05-08 12:01:16

  • Adds a custom operator >>> for chaining image transformers

Submodule Fixup - 2018-04-27 14:09:47

Escape - 2018-04-13 18:51:48

  • Replacing slashes with dashes in cache keys. Thanks to @CaileanWilkinson

Added support for multiple completion handlers - 2018-04-12 19:29:08

  • Support for multiple completion handlers. Thanks to @CaileanWilkinson

Swift 4.1 - 2018-03-31 15:14:13