A lightweight generic cache for iOS written in Swift with extra love for images.

Related tags

Image HanekeSwift
Overview

Haneke

Carthage compatible SwiftPM compatible Accio supported Platform Build Status Join the chat at https://gitter.im/Haneke/HanekeSwift

Haneke is a lightweight generic cache for iOS and tvOS written in Swift 4. It's designed to be super-simple to use. Here's how you would initalize a JSON cache and fetch objects from a url:

let cache = Cache<JSON>(name: "github")
let URL = NSURL(string: "https://api.github.com/users/haneke")!

cache.fetch(URL: URL).onSuccess { JSON in
    print(JSON.dictionary?["bio"])
}

Haneke provides a memory and LRU disk cache for UIImage, NSData, JSON, String or any other type that can be read or written as data.

Particularly, Haneke excels at working with images. It includes a zero-config image cache with automatic resizing. Everything is done in background, allowing for fast, responsive scrolling. Asking Haneke to load, resize, cache and display an appropriately sized image is as simple as:

imageView.hnk_setImageFromURL(url)

Really.

Features

  • Generic cache with out-of-the-box support for UIImage, NSData, JSON and String
  • First-level memory cache using NSCache
  • Second-level LRU disk cache using the file system
  • Asynchronous fetching of original values from network or disk
  • All disk access is performed in background
  • Thread-safe
  • Automatic cache eviction on memory warnings or disk capacity reached
  • Comprehensive unit tests
  • Extensible by defining custom formats, supporting additional types or implementing custom fetchers

For images:

  • Zero-config UIImageView and UIButton extensions to use the cache, optimized for UITableView and UICollectionView cell reuse
  • Background image resizing and decompression

Installation

Using CocoaPods:

use_frameworks!
pod 'HanekeSwift'

Using Carthage:

github "Haneke/HanekeSwift"

Using SwiftPM or Accio:

.package(url: "https://github.com/Haneke/HanekeSwift.git", .upToNextMajor(from: "0.11.2")),

Then link Haneke in your App target like so:

.target(
    name: "App",
    dependencies: [
        "Haneke",
    ]
),

Manually:

  1. Drag Haneke.xcodeproj to your project in the Project Navigator.
  2. Select your project and then your app target. Open the Build Phases panel.
  3. Expand the Target Dependencies group, and add Haneke.framework.
  4. Click on the + button at the top left of the panel and select New Copy Files Phase. Set Destination to Frameworks, and add Haneke.framework.
  5. import Haneke whenever you want to use Haneke.

Requirements

  • iOS 8.0+ or tvOS 9.1+
  • Swift 4

Using the cache

Haneke provides shared caches for UIImage, NSData, JSON and String. You can also create your own caches.

The cache is a key-value store. For example, here's how you would cache and then fetch some data.

let cache = Shared.dataCache

cache.set(value: data, key: "funny-games.mp4")

// Eventually...

cache.fetch(key: "funny-games.mp4").onSuccess { data in
    // Do something with data
}

In most cases the value will not be readily available and will have to be fetched from network or disk. Haneke offers convenience fetch functions for these cases. Let's go back to the first example, now using a shared cache:

let cache = Shared.JSONCache
let URL = NSURL(string: "https://api.github.com/users/haneke")!

cache.fetch(URL: URL).onSuccess { JSON in
   print(JSON.dictionary?["bio"])
}

The above call will first attempt to fetch the required JSON from (in order) memory, disk or NSURLCache. If not available, Haneke will fetch the JSON from the source, return it and then cache it. In this case, the URL itself is used as the key.

Further customization can be achieved by using formats, supporting additional types or implementing custom fetchers.

Extra ♡ for images

Need to cache and display images? Haneke provides convenience methods for UIImageView and UIButton with optimizations for UITableView and UICollectionView cell reuse. Images will be resized appropriately and cached in a shared cache.

// Setting a remote image
imageView.hnk_setImageFromURL(url)

// Setting an image manually. Requires you to provide a key.
imageView.hnk_setImage(image, key: key)

The above lines take care of:

  1. If cached, retrieving an appropriately sized image (based on the bounds and contentMode of the UIImageView) from the memory or disk cache. Disk access is performed in background.
  2. If not cached, loading the original image from web/memory and producing an appropriately sized image, both in background. Remote images will be retrieved from the shared NSURLCache if available.
  3. Setting the image and animating the change if appropriate.
  4. Or doing nothing if the UIImageView was reused during any of the above steps.
  5. Caching the resulting image.
  6. If needed, evicting the least recently used images in the cache.

Formats

Formats allow to specify the disk cache size and any transformations to the values before being cached. For example, the UIImageView extension uses a format that resizes images to fit or fill the image view as needed.

You can also use custom formats. Say you want to limit the disk capacity for icons to 10MB and apply rounded corners to the images. This is how it could look like:

let cache = Shared.imageCache

let iconFormat = Format<UIImage>(name: "icons", diskCapacity: 10 * 1024 * 1024) { image in
    return imageByRoundingCornersOfImage(image)
}
cache.addFormat(iconFormat)

let URL = NSURL(string: "http://haneke.io/icon.png")!
cache.fetch(URL: URL, formatName: "icons").onSuccess { image in
    // image will be a nice rounded icon
}

Because we told the cache to use the "icons" format Haneke will execute the format transformation in background and return the resulting value.

Formats can also be used from the UIKit extensions:

imageView.hnk_setImageFromURL(url, format: iconFormat)

Fetchers

The fetch functions for urls and paths are actually convenience methods. Under the hood Haneke uses fetcher objects. To illustrate, here's another way of fetching from a url by explictly using a network fetcher:

let URL = NSURL(string: "http://haneke.io/icon.png")!
let fetcher = NetworkFetcher<UIImage>(URL: URL)
cache.fetch(fetcher: fetcher).onSuccess { image in
    // Do something with image
}

Fetching an original value from network or disk is an expensive operation. Fetchers act as a proxy for the value, and allow Haneke to perform the fetch operation only if absolutely necessary.

In the above example the fetcher will be executed only if there is no value associated with "http://haneke.io/icon.png" in the memory or disk cache. If that happens, the fetcher will be responsible from fetching the original value, which will then be cached to avoid further network activity.

Haneke provides two specialized fetchers: NetworkFetcher<T> and DiskFetcher<T>. You can also implement your own fetchers by subclassing Fetcher<T>.

Custom fetchers

Through custom fetchers you can fetch original values from other sources than network or disk (e.g., Core Data), or even change how Haneke acceses network or disk (e.g., use Alamofire for networking instead of NSURLSession). A custom fetcher must subclass Fetcher<T> and is responsible for:

  • Providing the key (e.g., NSURL.absoluteString in the case of NetworkFetcher) associated with the value to be fetched
  • Fetching the value in background and calling the success or failure closure accordingly, both in the main queue
  • Cancelling the fetch on demand, if possible

Fetchers are generic, and the only restriction on their type is that it must implement DataConvertible.

Supporting additional types

Haneke can cache any type that can be read and saved as data. This is indicated to Haneke by implementing the protocols DataConvertible and DataRepresentable.

public protocol DataConvertible {
    typealias Result

    class func convertFromData(data:NSData) -> Result?

}

public protocol DataRepresentable {

    func asData() -> NSData!

}

This is how one could add support for NSDictionary:

extension NSDictionary : DataConvertible, DataRepresentable {

    public typealias Result = NSDictionary

    public class func convertFromData(data:NSData) -> Result? {
        return NSKeyedUnarchiver.unarchiveObjectWithData(data) as? NSDictionary
    }

    public func asData() -> NSData! {
        return NSKeyedArchiver.archivedDataWithRootObject(self)
    }

}

Then creating a NSDictionary cache would be as simple as:

let cache = Cache<NSDictionary>(name: "dictionaries")

Roadmap

Haneke Swift is in initial development and its public API should not be considered stable.

License

Copyright 2014 Hermes Pique (@hpique)
                 2014 Joan Romano (@joanromano)
                 2014 Luis Ascorbe (@lascorbe)
                 2014 Oriol Blanc (@oriolblanc)

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Comments
  • EXC_BAD_ACCESS in UIImage+Haneke.swift

    EXC_BAD_ACCESS in UIImage+Haneke.swift

    Line 56:

    if let context = CGBitmapContextCreate(nil, UInt(pixelSize.width), UInt(pixelSize.height), CGImageGetBitsPerComponent(originalImageRef), 0, colorSpace, bitmapInfo) {
    

    This is happening during app startup in simulator... run it again, and it usually works. Seen it several times now. XCode 6.1, iOS 8.1.

    Will try to post more info + trace next time I see it.

    bug 
    opened by SteveNewhouse 48
  • Support iOS7

    Support iOS7

    Swift apps can run on iOS7. It'd be nice if I could still use HanekeSwift on iOS7 too. Obviously iOS7 doesn't support frameworks so including Haneke in my app won't be as simple, but is there any reason Haneke wouldn't work on iOS7? Or you using (or planning to use) iOS8 specific APIs?

    enhancement help wanted question 
    opened by jmacmullin 33
  • Caching file, returning disk URL to retrieve later

    Caching file, returning disk URL to retrieve later

    Hey there!

    I have a requirement to cache video data, but then retrieve the URL location for that data. The reason for this is an AVAsset cannot be created using NSData, only via a URL.

    A very hacky (and very unreliable) way to do it now via Haneke is to do the following:

    let cache = Haneke.sharedDataCache
    cache.fetch(URL: URL).onSuccess { (data) in
      // Hacky way of getting cache URL from Haneke
      let path = DiskCache(name: "shared-data", capacity: UINT64_MAX).pathForKey(URL.absoluteString!)
      let cacheURL = NSURL(fileURLWithPath: path)
    }
    

    What are your thoughts on how this should be handled? Should I forego using Haneke for this specific feature and build a disk-only cache instead?

    James

    question 
    opened by jamescmartinez 21
  • Issue #115 - Synchronise access to UIImage with data to avoid crash

    Issue #115 - Synchronise access to UIImage with data to avoid crash

    It seems that UIImage with data constructor is not thread safe. Having two simultaneous threads accessing it was creating the Issue #115 reported already by many. Added NSLock to synchronise access between the several threads…

    opened by paulosotu 18
  • Swift 1.2 compile issues

    Swift 1.2 compile issues

    Lots of compile issues with Swift 1.2 (not unique to this library, FWIW). Tried the auto-convert to 1.2 and that did not resolve them all.

    Tried fixing other manually but not familiar enough with the 1.2 migration issues to work through it.

    enhancement 
    opened by SteveNewhouse 13
  • Swift 3 Support

    Swift 3 Support

    Hey guys,

    I saw that theres a branch feature/swift-3 but it doesn't seem to be maintained. Are there any news regarding Swift 3 support? Would be great!

    opened by ctews 12
  • Getting EXC_BAD_INSTRUCTION sometimes while trying to fetch from cache

    Getting EXC_BAD_INSTRUCTION sometimes while trying to fetch from cache

    Sometimes the app gets an EXC_BAD_INSTRUCTION while trying to fetch a string from cache. The cache fetching is done in a NSOperation subclass (with a maxConcurrentOperation of 10). Console ouput says malloc: *** error for object 0x7fb133c5d850: double free *** set a breakpoint in malloc_error_break to debug I tried to set a breakpoint without success. Anything I did wrong?

    duplicate 
    opened by coryoso 11
  • Haneke with SwiftyJSON: 'JSON' is ambiguous for type lookup in this context

    Haneke with SwiftyJSON: 'JSON' is ambiguous for type lookup in this context

    Hello, I am working on a project that includes both SwiftyJSON and Haneke as Pods from Cocoapods. I import SwiftyJSON and HanekeSwift in my AppDelegate. However I am getting 'JSON' is ambiguous for type lookup in this context in this line statement var chatChannels: Array<JSON>?. Same thing applies if I try to only include HanekeSwift in a UITableViewCell subclass where I need to load some images from the cache.

    Any ideas?

    question 
    opened by attheodo 9
  • Updated to swift 5 and fixed all warnings.

    Updated to swift 5 and fixed all warnings.

    This PR updates HanekeSwift to swift 5.0 and Xcode 10.2.

    [Updated]

    • Updates Swift Language Version to swift 5 and Xcode 10.2.
    • Travis.yml to use Xcode 10.2
    • Podspec bump.

    [Fixed]

    • All compiler warnings.
    opened by kevnm67 8
  • May 2017, Cannot build with carthage? (or anything?)

    May 2017, Cannot build with carthage? (or anything?)

    Very sadly this excellent project seems to be dead ?

    $ cat /var/folders/xh/m9fl5v8j4hv5mpt6pc85tjz80000gn/T/carthage-xcodebuild.r92iz1.log
    /usr/bin/xcrun xcodebuild -workspace../Carthage/Checkouts/HanekeSwift/Haneke.xcworkspace -scheme Haneke -configuration Release -derivedDataPath ../Library/Caches/org.carthage.CarthageKit/DerivedData/HanekeSwift/v0.10.1 -sdk iphoneos ONLY_ACTIVE_ARCH=NO BITCODE_GENERATION_MODE=bitcode CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= CARTHAGE=YES clean buildUser defaults from command line:
        IDEDerivedDataPathOverride = ../Library/Caches/org.carthage.CarthageKit/DerivedData/HanekeSwift/v0.10.1
    
    Build settings from command line:
        BITCODE_GENERATION_MODE = bitcode
        CARTHAGE = YES
        CODE_SIGN_IDENTITY = 
        CODE_SIGNING_REQUIRED = NO
        ONLY_ACTIVE_ARCH = NO
        SDKROOT = iphoneos10.3
    
    --- xcodebuild: WARNING: Unable to open project file ../ios/Carthage/Checkouts/HanekeSwift/Haneke.playground' in workspace '../ios/Carthage/Checkouts/HanekeSwift/Haneke.xcworkspace'.
    === CLEAN TARGET Haneke OF PROJECT Haneke WITH CONFIGURATION Release ===
    
    Check dependencies
    “Swift Language Version” (SWIFT_VERSION) is required to be configured correctly for targets which use Swift. Use the [Edit > Convert > To Current Swift Syntax…] menu to choose a Swift version or use the Build Settings editor to configure the build setting directly.
    “Swift Language Version” (SWIFT_VERSION) is required to be configured correctly for targets which use Swift. Use the [Edit > Convert > To Current Swift Syntax…] menu to choose a Swift version or use the Build Settings editor to configure the build setting directly.
    
    ** CLEAN FAILED **
    
    
    The following build commands failed:
    	Check dependencies
    (1 failure)
    === BUILD TARGET Haneke OF PROJECT Haneke WITH CONFIGURATION Release ===
    
    Check dependencies
    “Swift Language Version” (SWIFT_VERSION) is required to be configured correctly for targets which use Swift. Use the [Edit > Convert > To Current Swift Syntax…] menu to choose a Swift version or use the Build Settings editor to configure the build setting directly.
    “Swift Language Version” (SWIFT_VERSION) is required to be configured correctly for targets which use Swift. Use the [Edit > Convert > To Current Swift Syntax…] menu to choose a Swift version or use the Build Settings editor to configure the build setting directly.
    
    ** BUILD FAILED **
    
    
    opened by smhk 8
  • Swift 3 upgrade error...

    Swift 3 upgrade error...

    Got the following for a swift 3 migration upgrade for haneke swift... was wondering how to resolve this. Thanks!

    
    Analyzing dependencies
    Pre-downloading: `HanekeSwift` from `https://github.com/Haneke/HanekeSwift/tree/feature/swift-3`
    
    [!] Error installing HanekeSwift
    [!] /Applications/CocoaPods.app/Contents/Resources/bundle/bin/git clone https://github.com/Haneke/HanekeSwift/tree/feature/swift-3 /var/folders/3_/s_7hqrn93rz07b_4rtq0_c6r0000gp/T/d20161122-65725-c3x8io --template= --single-branch --depth 1
    
    Cloning into '/var/folders/3_/s_7hqrn93rz07b_4rtq0_c6r0000gp/T/d20161122-65725-c3x8io'...
    fatal: repository 'https://github.com/Haneke/HanekeSwift/tree/feature/swift-3/' not found
    
    
    opened by rlam3 7
  • Package.swift not included in any release

    Package.swift not included in any release

    Package.swift is checked into master but the latest (or any) release v0.11.1 does not include Package.swift so this package can't be added to a project via Swift Package Manager.

    opened by dustinburkedev 1
  • Compiling with carthage not possible with Xcode 12.0

    Compiling with carthage not possible with Xcode 12.0

    Even after carthage update, it´s still not possible to compile. Does anyone has an idea how to fix this problem? Or is it possible to make an update which will fix this issue? Thanks in advance.

    opened by Maventadorian 1
  • Troubleshooting when success is not success

    Troubleshooting when success is not success

    I never see this in my own testing but Sentry crash reports show that some real-world users are getting the following issue. I wonder how I continue to diagnose it.

    TL;DR

    Fetch (NetworkFetcher) calls the success closure but the data is apparently not ok.

               myCache.fetch(URL: url, failure: {error in
                    print("Image fetch error \(String(describing: error)) setting image \(url)")
                }, success: {data in
                    print("loaded image: \(url)")
                    if let image = UIImage(data: data) {
                        self.scrollView.display(image: image)
                    } else {
                        // This is where I want to figure out why data is not actually the image data.
                        // Would it make sense to remove this item from the cache here and have it re-download?
                    }
                })
    

    Questions / Ideas

    • Is Haneke caching the http response for 4XX or 5XX results? Then I might occasionally get a bad result from a sad server into the cache.

    • Some users could have a lot of images. Could this be a timing issue where the app gets a memory warning and the data is cleared before my code uses it to make a UIImage?

    opened by eimermusic 0
  • Create intermediate directories before writing to a file

    Create intermediate directories before writing to a file

    This pull request makes sure, that before a file is written to the disk, the folders in the path it should be written to exists. All the needed intermediate directories are created, so that the data can be written to the file without failing due to a non existing directory.

    Some already mentioned in #371 and #245, that after the removeAll() method of a cache is called, the folders are deleted, but not recreated directly. So the writes after calling removeAll() are failing with an error.

    opened by JustusvonBrandt 0
Releases(0.11.0)
  • 0.11.0(Feb 15, 2018)

  • v0.10.1(Jan 2, 2016)

    Bug fixes and improvements without API changes. Highly recommended to upgrade. Highlights:

    • #115: Bug fix: Synchronize access to UIImage initializer to workaround around Apple bug that caused rare crashes. Thanks @paulosotu!
    • 5fff29f52a0a6e290934974b8270cf45044a2bd0: [UIKit] Bug fix: Don't animate with zero duration to prevent flicker in some situations. Thanks @dstancioff!
    • #228: [NetworkFetcher] Support file:// uris by @jasoncabot.
    • e452c3cfed23896433a7f9335543565b4d3b0df0 [NetworkFetcher] Support 201 responses as suggested by @barbelith.
    • 0e79dd9b48d5477d6936b1ccb2ca6538dc52bc6f: [UIKit] Increase disk capacity for defaults formats to 50MB as suggested by @sebbean.
    • e185dd39686321aa93dc9d728b4b1d1cf7856032: [DiskFetcher] Don't fail if already cancelled.
    • #193: [DiskCache] Check if file exists before updating access time by @s0meone.
    • #253: Enable "Require Only App-Extension-Safe API" to remove warning by @poolqf.

    Last but not least a warn welcome and much appreciation to @dcharbonnier who just joined the Haneke Swift team and has already been reviewing pull requests left and right!

    Source code(tar.gz)
    Source code(zip)
Owner
Haneke
A lightweight zero-config image cache for iOS, in Swift and Objective-C.
Haneke
🚀SwiftUI Image downloader with performant LRU mem/disk cache.

Progressive concurrent image downloader for SwiftUI, with neat API and performant LRU mem/disk cache.

Cheng Zhang 42 Sep 24, 2022
Asynchronous image downloader with cache support as a UIImageView category

This library provides an async image downloader with cache support. For convenience, we added categories for UI elements like UIImageView, UIButton, M

null 24.4k Jan 5, 2023
DGImageView - Asynchronous image downloader with cache. Supports gif too

DGImageView Installation Usage DGImageView Asynchronous image downloader with cache. Supports gif, memory cache, disk cache features. Installation Xco

donggyu 1 Jan 1, 2022
CachedAsyncImage is the simplest way to add cache to your AsyncImage.

SwiftUI CachedAsyncImage ??️ CachedAsyncImage is AsyncImage, but with cache capabilities. Usage CachedAsyncImage has the exact same API and behavior a

Lorenzo Fiamingo 278 Jan 5, 2023
Agrume - 🍋 An iOS image viewer written in Swift with support for multiple images.

Agrume An iOS image viewer written in Swift with support for multiple images. Requirements Swift 5.0 iOS 9.0+ Xcode 10.2+ Installation Use Swift Packa

Jan Gorman 601 Dec 26, 2022
Nilay Dagdemir 0 Jan 23, 2022
A simple macOS app to read code from images, written purely in Swift using Vision Framework.

CodeReader A simple macOS app to read code from images, written purely in Swift using Vision Framework. Usage Drag an image Click the convert button R

Md Ibrahim Hassan 44 Nov 20, 2022
A lightweight and fast image loader for iOS written in Swift.

ImageLoader ImageLoader is an instrument for asynchronous image loading written in Swift. It is a lightweight and fast image loader for iOS. Features

Hirohisa Kawasaki 293 Nov 24, 2022
iOS Swift class to create circular or rounded avatar images

SwiftyAvatar iOS Swift 3.0 UIimage class Create awesome circular avatar images! IBInspectable attributes accessible from the identity inspector. Round

Dimitrios Kalaitzidis 183 Dec 17, 2022
APNGKit is a high performance framework for loading and displaying APNG images in iOS and macOS.

APNGKit is a high performance framework for loading and displaying APNG images in iOS and macOS. It's built on top of a modified version of libpng wit

Wei Wang 2.1k Dec 30, 2022
📱iOS app to extract full-resolution video frames as images.

Frame Grabber is a focused, easy-to-use iOS app to extract full-resolution video frames as images. Perfect to capture and share your favorite video mo

Arthur Hammer 319 Jan 7, 2023
Jogendra 113 Nov 28, 2022
iOS library for quickly displaying images while scrolling

Fast Image Cache is an efficient, persistent, and—above all—fast way to store and retrieve images in your iOS application. Part of any good iOS applic

Path Mobile Inc Pte. Ltd. 8.2k Jan 9, 2023
iOS SDK to share JPEG images with an expiration date

Ebblink iOS SDK A library to integrate Ebblink private image sharing capabilities into your iOS app. Table of Contents Getting Started Requirements Se

null 4 Apr 6, 2018
iOS Framework that makes it easy to preview images on any UIImageView.

AZImagePreview iOS Framework that makes it easy to preview images on any UIImageView. Screenshots Installation: Cocoa Pods: pod 'AZImagePreview' Swift

Antonio Zaitoun 25 Dec 11, 2022
FlaneurImagePicker is an iOS image picker that allows users to pick images from different sources (ex: user's library, user's camera, Instagram...). It's highly customizable.

FlaneurImagePicker is a highly customizable iOS image picker that allows users to pick images from different sources (ex: device's library, device's c

FlaneurApp 17 Feb 2, 2020
Kingfisher is a powerful, pure-Swift library for downloading and caching images from the web

Kingfisher is a powerful, pure-Swift library for downloading and caching images from the web. It provides you a chance to use a pure-Swift way to work

Wei Wang 20.9k Dec 30, 2022
SwiftGen is a tool to automatically generate Swift code for resources of your projects (like images, localised strings, etc), to make them type-safe to use.

SwiftGen is a tool to automatically generate Swift code for resources of your projects (like images, localised strings, etc), to make them type-safe to use.

null 8.3k Jan 5, 2023
A high-performance image library for downloading, caching, and processing images in Swift.

Features Asynchronous image downloader with priority queuing Advanced memory and database caching using YapDatabase (SQLite) Guarantee of only one ima

Yap Studios 72 Sep 19, 2022