Skip to content
Merged
34 changes: 28 additions & 6 deletions Cache.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
D5291C3A1C28220B00B702C9 /* StorageAware.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291C261C28220B00B702C9 /* StorageAware.swift */; };
D5291C3B1C28220B00B702C9 /* StorageFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291C271C28220B00B702C9 /* StorageFactory.swift */; };
D5291C6C1C2827FB00B702C9 /* BasicHybridCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291C6A1C2827FB00B702C9 /* BasicHybridCache.swift */; };
D5291C6D1C2827FB00B702C9 /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291C6B1C2827FB00B702C9 /* Cache.swift */; };
D5291C731C28296B00B702C9 /* HybridCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291C721C28296B00B702C9 /* HybridCache.swift */; };
D5291D1D1C2837DB00B702C9 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5DC59E01C20593E003BD79B /* Cache.framework */; };
D5291D351C28389B00B702C9 /* SpecHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291CDF1C28374800B702C9 /* SpecHelper.swift */; };
Expand All @@ -53,7 +52,6 @@
D5291D7E1C283BF200B702C9 /* HybridCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291D7A1C283BE300B702C9 /* HybridCache.swift */; };
D5291D851C283C7C00B702C9 /* SpecHelper+OSX.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291D811C283C7000B702C9 /* SpecHelper+OSX.swift */; };
D5291D861C283CFB00B702C9 /* BasicHybridCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291C6A1C2827FB00B702C9 /* BasicHybridCache.swift */; };
D5291D871C283CFB00B702C9 /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291C6B1C2827FB00B702C9 /* Cache.swift */; };
D5291D881C283CFB00B702C9 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291C151C28220B00B702C9 /* Config.swift */; };
D5291D891C283CFB00B702C9 /* Cachable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291C171C28220B00B702C9 /* Cachable.swift */; };
D5291D8A1C283CFB00B702C9 /* Capsule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291C181C28220B00B702C9 /* Capsule.swift */; };
Expand All @@ -74,6 +72,15 @@
D5291D9E1C283EC000B702C9 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5291CDA1C2835D000B702C9 /* Nimble.framework */; };
D5291DA11C28405900B702C9 /* UIImage+CacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291DA01C28405900B702C9 /* UIImage+CacheTests.swift */; };
D5291DA31C2841D200B702C9 /* NSImage+CacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291DA21C2841D200B702C9 /* NSImage+CacheTests.swift */; };
D5ACACC91CD01F3400567809 /* SyncCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACACC81CD01F3400567809 /* SyncCache.swift */; };
D5ACACCA1CD01F3400567809 /* SyncCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACACC81CD01F3400567809 /* SyncCache.swift */; };
D5ACACCC1CD0207300567809 /* SyncHybridCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACACCB1CD0207300567809 /* SyncHybridCache.swift */; };
D5ACACCD1CD0207300567809 /* SyncHybridCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACACCB1CD0207300567809 /* SyncHybridCache.swift */; };
D5ACACD11CD0228400567809 /* SyncCacheSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACACCE1CD0227200567809 /* SyncCacheSpec.swift */; };
D5ACACD51CD0256700567809 /* SyncHybridCacheSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACACD21CD0254300567809 /* SyncHybridCacheSpec.swift */; };
D5ACACD61CD0256700567809 /* SyncHybridCacheSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACACD21CD0254300567809 /* SyncHybridCacheSpec.swift */; };
D5ACACDE1CD0272600567809 /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACACDD1CD0272600567809 /* Cache.swift */; };
D5ACACDF1CD0272600567809 /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACACDD1CD0272600567809 /* Cache.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -114,7 +121,6 @@
D5291C261C28220B00B702C9 /* StorageAware.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StorageAware.swift; sourceTree = "<group>"; };
D5291C271C28220B00B702C9 /* StorageFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StorageFactory.swift; sourceTree = "<group>"; };
D5291C6A1C2827FB00B702C9 /* BasicHybridCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasicHybridCache.swift; sourceTree = "<group>"; };
D5291C6B1C2827FB00B702C9 /* Cache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cache.swift; sourceTree = "<group>"; };
D5291C721C28296B00B702C9 /* HybridCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HybridCache.swift; sourceTree = "<group>"; };
D5291CDA1C2835D000B702C9 /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/Mac/Nimble.framework; sourceTree = "<group>"; };
D5291CDF1C28374800B702C9 /* SpecHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpecHelper.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -147,6 +153,11 @@
D5291DA21C2841D200B702C9 /* NSImage+CacheTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSImage+CacheTests.swift"; sourceTree = "<group>"; };
D5643E351C43F2CC00582E17 /* CustomCache.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = CustomCache.playground; sourceTree = "<group>"; };
D5643E361C43F2CC00582E17 /* HybridCache.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = HybridCache.playground; sourceTree = "<group>"; };
D5ACACC81CD01F3400567809 /* SyncCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncCache.swift; sourceTree = "<group>"; };
D5ACACCB1CD0207300567809 /* SyncHybridCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncHybridCache.swift; sourceTree = "<group>"; };
D5ACACCE1CD0227200567809 /* SyncCacheSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncCacheSpec.swift; sourceTree = "<group>"; };
D5ACACD21CD0254300567809 /* SyncHybridCacheSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncHybridCacheSpec.swift; sourceTree = "<group>"; };
D5ACACDD1CD0272600567809 /* Cache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cache.swift; sourceTree = "<group>"; };
D5DC59E01C20593E003BD79B /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D5DC5A181C205AC9003BD79B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D5DC5A6C1C205C2A003BD79B /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quick.framework; path = Carthage/Build/iOS/Quick.framework; sourceTree = "<group>"; };
Expand Down Expand Up @@ -224,7 +235,7 @@
isa = PBXGroup;
children = (
D5291C6A1C2827FB00B702C9 /* BasicHybridCache.swift */,
D5291C6B1C2827FB00B702C9 /* Cache.swift */,
D5ACACDD1CD0272600567809 /* Cache.swift */,
D5291C151C28220B00B702C9 /* Config.swift */,
D5291C161C28220B00B702C9 /* DataStructures */,
D5291C1C1C28220B00B702C9 /* Extensions */,
Expand Down Expand Up @@ -261,6 +272,8 @@
isa = PBXGroup;
children = (
D5291C221C28220B00B702C9 /* DefaultCacheConverter.swift */,
D5ACACC81CD01F3400567809 /* SyncCache.swift */,
D5ACACCB1CD0207300567809 /* SyncHybridCache.swift */,
);
path = Library;
sourceTree = "<group>";
Expand Down Expand Up @@ -336,6 +349,8 @@
isa = PBXGroup;
children = (
D5291CEF1C28374800B702C9 /* DefaultCacheConverterSpec.swift */,
D5ACACCE1CD0227200567809 /* SyncCacheSpec.swift */,
D5ACACD21CD0254300567809 /* SyncHybridCacheSpec.swift */,
);
path = Library;
sourceTree = "<group>";
Expand Down Expand Up @@ -702,6 +717,8 @@
D5291DA11C28405900B702C9 /* UIImage+CacheTests.swift in Sources */,
D5291D381C28389B00B702C9 /* ConfigSpec.swift in Sources */,
D5291D431C28389B00B702C9 /* MemoryStorageSpec.swift in Sources */,
D5ACACD11CD0228400567809 /* SyncCacheSpec.swift in Sources */,
D5ACACD51CD0256700567809 /* SyncHybridCacheSpec.swift in Sources */,
D5291D401C28389B00B702C9 /* String+CacheSpec.swift in Sources */,
D5291D9A1C283DB300B702C9 /* UIImage+CacheSpec.swift in Sources */,
D5291D411C28389B00B702C9 /* DefaultCacheConverterSpec.swift in Sources */,
Expand All @@ -716,7 +733,9 @@
files = (
D5291D941C283CFB00B702C9 /* MemoryStorage.swift in Sources */,
D5291D921C283CFB00B702C9 /* DefaultCacheConverter.swift in Sources */,
D5ACACCA1CD01F3400567809 /* SyncCache.swift in Sources */,
D5291D8B1C283CFB00B702C9 /* Expiry.swift in Sources */,
D5ACACDF1CD0272600567809 /* Cache.swift in Sources */,
D5291D891C283CFB00B702C9 /* Cachable.swift in Sources */,
D5291D961C283CFB00B702C9 /* StorageFactory.swift in Sources */,
D5291D7E1C283BF200B702C9 /* HybridCache.swift in Sources */,
Expand All @@ -726,11 +745,11 @@
D5291D7D1C283BF200B702C9 /* NSImage+Cache.swift in Sources */,
D5291D881C283CFB00B702C9 /* Config.swift in Sources */,
D5291D951C283CFB00B702C9 /* StorageAware.swift in Sources */,
D5291D871C283CFB00B702C9 /* Cache.swift in Sources */,
D5291D911C283CFB00B702C9 /* String+Cache.swift in Sources */,
D5291D901C283CFB00B702C9 /* NSDate+Cache.swift in Sources */,
D5291D931C283CFB00B702C9 /* DiskStorage.swift in Sources */,
D5291D861C283CFB00B702C9 /* BasicHybridCache.swift in Sources */,
D5ACACCD1CD0207300567809 /* SyncHybridCache.swift in Sources */,
D5291D8D1C283CFB00B702C9 /* StorageKind.swift in Sources */,
D5291D8F1C283CFB00B702C9 /* NSData+Cache.swift in Sources */,
);
Expand All @@ -742,6 +761,7 @@
files = (
D5291D9C1C283DD900B702C9 /* NSImage+CacheSpec.swift in Sources */,
D5291D851C283C7C00B702C9 /* SpecHelper+OSX.swift in Sources */,
D5ACACD61CD0256700567809 /* SyncHybridCacheSpec.swift in Sources */,
D5291DA31C2841D200B702C9 /* NSImage+CacheTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -752,7 +772,9 @@
files = (
D5291C2E1C28220B00B702C9 /* Cachable.swift in Sources */,
D5291C311C28220B00B702C9 /* JSON.swift in Sources */,
D5ACACC91CD01F3400567809 /* SyncCache.swift in Sources */,
D5291C361C28220B00B702C9 /* String+Cache.swift in Sources */,
D5ACACDE1CD0272600567809 /* Cache.swift in Sources */,
D5291C341C28220B00B702C9 /* NSData+Cache.swift in Sources */,
D5291C3A1C28220B00B702C9 /* StorageAware.swift in Sources */,
D5291C381C28220B00B702C9 /* DiskStorage.swift in Sources */,
Expand All @@ -761,12 +783,12 @@
D5291C291C28220B00B702C9 /* UIImage+Cache.swift in Sources */,
D5291C351C28220B00B702C9 /* NSDate+Cache.swift in Sources */,
D5291C371C28220B00B702C9 /* DefaultCacheConverter.swift in Sources */,
D5291C6D1C2827FB00B702C9 /* Cache.swift in Sources */,
D5291C321C28220B00B702C9 /* StorageKind.swift in Sources */,
D5291C301C28220B00B702C9 /* Expiry.swift in Sources */,
D5291C331C28220B00B702C9 /* JSON+Cache.swift in Sources */,
D5291C2F1C28220B00B702C9 /* Capsule.swift in Sources */,
D5291C2D1C28220B00B702C9 /* Config.swift in Sources */,
D5ACACCC1CD0207300567809 /* SyncHybridCache.swift in Sources */,
D5291C6C1C2827FB00B702C9 /* BasicHybridCache.swift in Sources */,
D5291C731C28296B00B702C9 /* HybridCache.swift in Sources */,
);
Expand Down
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![License](https://img.shields.io/cocoapods/l/Cache.svg?style=flat)](http://cocoadocs.org/docsets/Cache)
[![Platform](https://img.shields.io/cocoapods/p/Cache.svg?style=flat)](http://cocoadocs.org/docsets/Cache)
[![Documentation](https://img.shields.io/cocoapods/metrics/doc-percent/Cache.svg?style=flat)](http://cocoadocs.org/docsets/Cache)
![Swift](https://img.shields.io/badge/%20in-swift%202.2-orange.svg)

## Table of Contents
Expand All @@ -14,6 +15,8 @@
* [Usage](#usage)
* [Hybrid cache](#hybrid-cache)
* [Type safe cache](#type-safe-cache)
* [SyncCache](#sync-cache)
* [SyncHybridCache](#sync-hybrid-cache)
* [Expiry date](#expiry-date)
* [Cachable protocol](#cachable-protocol)
* [Optional bonuses](#optional-bonuses)
Expand Down Expand Up @@ -158,6 +161,43 @@ cache.remove("image")
cache.clear()
```

### SyncHybridCache

`Cache` is born to be async, but if for some reason you need to perform cache
operations synchronously, there is a helper for that.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should read;

Cache was born to be async.


```swift
let cache = HybridCache(name: "Mix")
let syncCache = SyncHybridCache(cache)

// Add UIImage to cache synchronously
syncCache.add("image", object: UIImage(named: "image.png"))

// Retrieve image from cache synchronously
let image: UIImage? = syncCache.object("image")

// Remove an object from the cache
syncCache.remove("image")

// Clean the cache
syncCache.clear()
```

### SyncCache

`SyncCache` works exactly in the same way as `SyncHybridCache`, the only
difference is that it's a wrapper around a type safe cache.

```swift
let cache = Cache<UIImage>(name: "ImageCache")
let syncCache = SyncCache(cache)

syncCache.add("image", object: UIImage(named: "image.png"))
let image = syncCache.object("image")
syncCache.remove("image")
syncCache.clear()
```

### Expiry date

```swift
Expand Down
17 changes: 17 additions & 0 deletions Source/Mac/Extensions/NSImage+Cache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,26 @@ import Cocoa

// MARK: - Cachable

/**
Implementation of Cachable protocol.
*/
extension NSImage: Cachable {

public typealias CacheType = NSImage

/**
Creates UIImage from NSData

- Parameter data: Data to decode from
*/
public static func decode(data: NSData) -> CacheType? {
let image = NSImage(data: data)
return image
}

/**
Encodes UIImage to NSData
*/
public func encode() -> NSData? {
guard let data = TIFFRepresentation else { return nil }

Expand All @@ -25,8 +36,14 @@ extension NSImage: Cachable {

// MARK: - Helpers

/**
Helper UIImage extension.
*/
extension NSImage {

/**
Checks if image has alpha component
*/
var hasAlpha: Bool {
var imageRect:CGRect = CGRectMake(0, 0, size.width, size.height)
let imageRef = CGImageForProposedRect(&imageRect, context: nil, hints: nil)
Expand Down
23 changes: 23 additions & 0 deletions Source/Mac/HybridCache.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import Cocoa

/**
HybridCache supports storing all kinds of objects, as long as they conform to
Cachable protocol. It's two layered cache (with front and back storages), as well as Cache.
Subscribes to system notifications to clear expired cached objects.
*/
public class HybridCache: BasicHybridCache {

// MARK: - Inititalization

/**
Creates a new instance of BasicHybridCache and subscribes to system notifications.

- Parameter name: A name of the cache
- Parameter config: Cache configuration
*/
public override init(name: String, config: Config = Config.defaultConfig) {
super.init(name: name, config: config)

Expand All @@ -15,20 +26,32 @@ public class HybridCache: BasicHybridCache {
name: NSApplicationDidResignActiveNotification, object: nil)
}

/**
Removes notification center observer.
*/
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}

// MARK: - Notifications

/**
Clears expired cache items when the app recieves memory warning.
*/
func applicationDidReceiveMemoryWarning() {
frontStorage.clearExpired(nil)
}

/**
Clears expired cache items when the app terminates.
*/
func applicationWillTerminate() {
backStorage.clearExpired(nil)
}

/**
Clears expired cache items when the app resign active.
*/
func applicationDidResignActive() {
backStorage.clearExpired(nil)
}
Expand Down
39 changes: 39 additions & 0 deletions Source/Shared/BasicHybridCache.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
import Foundation

/**
BasicHybridCache supports storing all kinds of objects, as long as they conform to
Cachable protocol. It's two layered cache (with front and back storages)
*/
public class BasicHybridCache: NSObject {

/// A name of the cache
public let name: String

/// Cache configuration
let config: Config
/// Front cache (should be less time and memory consuming)
let frontStorage: StorageAware
// BAck cache (used for content that outlives the application life-cycle)
var backStorage: StorageAware

// MARK: - Inititalization

/**
Creates a new instance of BasicHybridCache.

- Parameter name: A name of the cache
- Parameter config: Cache configuration
*/
public init(name: String, config: Config = Config.defaultConfig) {
self.name = name
self.config = config
Expand All @@ -22,6 +36,14 @@ public class BasicHybridCache: NSObject {

// MARK: - Caching

/**
Adds passed object to the front and back cache storages.

- Parameter key: Unique key to identify the object in the cache
- Parameter object: Object that needs to be cached
- Parameter expiry: Expiration date for the cached object
- Parameter completion: Completion closure to be called when the task is done
*/
public func add<T: Cachable>(key: String, object: T, expiry: Expiry? = nil, completion: (() -> Void)? = nil) {
let expiry = expiry ?? config.expiry

Expand All @@ -37,6 +59,12 @@ public class BasicHybridCache: NSObject {
}
}

/**
Tries to retrieve the object from to the front and back cache storages.

- Parameter key: Unique key to identify the object in the cache
- Parameter completion: Completion closure returns object or nil
*/
public func object<T: Cachable>(key: String, completion: (object: T?) -> Void) {
frontStorage.object(key) { [weak self] (object: T?) in
if let object = object {
Expand All @@ -55,6 +83,12 @@ public class BasicHybridCache: NSObject {
}
}

/**
Removes the object from to the front and back cache storages.

- Parameter key: Unique key to identify the object in the cache
- Parameter completion: Completion closure to be called when the task is done
*/
public func remove(key: String, completion: (() -> Void)? = nil) {
frontStorage.remove(key) { [weak self] in
guard let weakSelf = self else {
Expand All @@ -68,6 +102,11 @@ public class BasicHybridCache: NSObject {
}
}

/**
Clears the front and back cache storages.

- Parameter completion: Completion closure to be called when the task is done
*/
public func clear(completion: (() -> Void)? = nil) {
frontStorage.clear() { [weak self] in
guard let weakSelf = self else {
Expand Down
Loading