Skip to content

Commit

Permalink
Wrap cache object in CacheEntry which will hold both object and metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
Kirmanie L Ravariere committed May 11, 2017
1 parent a2361a4 commit 072fd66
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 129 deletions.
18 changes: 9 additions & 9 deletions Cache.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
objects = {

/* Begin PBXBuildFile section */
57506FAE1EC29437009B71E9 /* ObjectMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57506FAD1EC29437009B71E9 /* ObjectMetadata.swift */; };
57506FBF1EC2E1B7009B71E9 /* ObjectMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57506FAD1EC29437009B71E9 /* ObjectMetadata.swift */; };
57506FC01EC2E1BA009B71E9 /* ObjectMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57506FAD1EC29437009B71E9 /* ObjectMetadata.swift */; };
57506FAE1EC29437009B71E9 /* CacheEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57506FAD1EC29437009B71E9 /* CacheEntry.swift */; };
57506FBF1EC2E1B7009B71E9 /* CacheEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57506FAD1EC29437009B71E9 /* CacheEntry.swift */; };
57506FC01EC2E1BA009B71E9 /* CacheEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57506FAD1EC29437009B71E9 /* CacheEntry.swift */; };
BDEDD3601DBCE5CE007416A6 /* BasicHybridCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291C6A1C2827FB00B702C9 /* BasicHybridCache.swift */; };
BDEDD3611DBCE5CE007416A6 /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACACDD1CD0272600567809 /* Cache.swift */; };
BDEDD3621DBCE5CE007416A6 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291C151C28220B00B702C9 /* Config.swift */; };
Expand Down Expand Up @@ -146,7 +146,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
57506FAD1EC29437009B71E9 /* ObjectMetadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectMetadata.swift; sourceTree = "<group>"; };
57506FAD1EC29437009B71E9 /* CacheEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CacheEntry.swift; sourceTree = "<group>"; };
BDEDD3561DBCE5B1007416A6 /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BDEDD3781DBCEB8A007416A6 /* Cache-tvOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Cache-tvOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
D5291C151C28220B00B702C9 /* Config.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -200,7 +200,7 @@
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>"; };
D5ACACDD1CD0272600567809 /* Cache.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = Cache.swift; sourceTree = "<group>"; tabWidth = 2; };
D5DC59E01C20593E003BD79B /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -326,7 +326,7 @@
D5291C251C28220B00B702C9 /* MemoryStorage.swift */,
D5291C261C28220B00B702C9 /* StorageAware.swift */,
D5291C271C28220B00B702C9 /* StorageFactory.swift */,
57506FAD1EC29437009B71E9 /* ObjectMetadata.swift */,
57506FAD1EC29437009B71E9 /* CacheEntry.swift */,
);
path = Storage;
sourceTree = "<group>";
Expand Down Expand Up @@ -845,7 +845,7 @@
BDEDD36D1DBCE5D8007416A6 /* SyncCache.swift in Sources */,
BDEDD36A1DBCE5D8007416A6 /* NSDate+Cache.swift in Sources */,
BDEDD36F1DBCE5D8007416A6 /* DiskStorage.swift in Sources */,
57506FC01EC2E1BA009B71E9 /* ObjectMetadata.swift in Sources */,
57506FC01EC2E1BA009B71E9 /* CacheEntry.swift in Sources */,
D5A138C21EB29BFA00881A20 /* UIImage+Cache.swift in Sources */,
BDEDD3601DBCE5CE007416A6 /* BasicHybridCache.swift in Sources */,
BDEDD3701DBCE5D8007416A6 /* MemoryStorage.swift in Sources */,
Expand Down Expand Up @@ -928,7 +928,7 @@
D5291D911C283CFB00B702C9 /* String+Cache.swift in Sources */,
D5291D901C283CFB00B702C9 /* NSDate+Cache.swift in Sources */,
D5A138C41EB29C2100881A20 /* NSImage+Cache.swift in Sources */,
57506FBF1EC2E1B7009B71E9 /* ObjectMetadata.swift in Sources */,
57506FBF1EC2E1B7009B71E9 /* CacheEntry.swift in Sources */,
D5291D931C283CFB00B702C9 /* DiskStorage.swift in Sources */,
D5291D861C283CFB00B702C9 /* BasicHybridCache.swift in Sources */,
D5ACACCD1CD0207300567809 /* SyncHybridCache.swift in Sources */,
Expand Down Expand Up @@ -967,7 +967,7 @@
D5291C321C28220B00B702C9 /* StorageKind.swift in Sources */,
D5291C301C28220B00B702C9 /* Expiry.swift in Sources */,
D5291C331C28220B00B702C9 /* JSON+Cache.swift in Sources */,
57506FAE1EC29437009B71E9 /* ObjectMetadata.swift in Sources */,
57506FAE1EC29437009B71E9 /* CacheEntry.swift in Sources */,
D5A138C11EB29BFA00881A20 /* UIImage+Cache.swift in Sources */,
D5291C2F1C28220B00B702C9 /* Capsule.swift in Sources */,
D5291C2D1C28220B00B702C9 /* Config.swift in Sources */,
Expand Down
51 changes: 27 additions & 24 deletions Source/Shared/BasicHybridCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,39 +102,42 @@ public class BasicHybridCache: NSObject {
- Parameter key: Unique key to identify the object in the cache
- Parameter completion: Completion closure returns object or nil
*/
func object<T: Cachable>(forKey key: String, completion: @escaping (_ object: T?) -> Void) {
frontStorage.object(key) { [weak self] (object: T?) in
if let object = object {
completion(object)
func object<T: Cachable>(forKey key: String, completion: @escaping (_ object: T?) -> Void){
cacheEntry(forKey: key) { (entry: CacheEntry<T>?) in
completion(entry?.object)
}
}

/**
Tries to retrieve the cache entry from to the front and back cache storages.
- Parameter key: Unique key to identify the cache entry in the cache
- Parameter completion: Completion closure returns cache entry or nil
*/
func cacheEntry<T: Cachable>(forKey key: String, completion: @escaping (_ object: CacheEntry<T>?) -> Void) {
frontStorage.cacheEntry(key) { [weak self] (entry: CacheEntry<T>?) in
if let entry = entry {
completion(entry)
return
}

guard let weakSelf = self else {
completion(object)
completion(entry)
return
}

weakSelf.backStorage.object(key) { (object: T?) in
guard let object = object else {
completion(nil)
return

weakSelf.backStorage.cacheEntry(key) { (entry: CacheEntry<T>?) in
guard let entry = entry else {
completion(nil)
return
}

weakSelf.frontStorage.add(key, object: entry.object, expiry: entry.expiry) { _ in
completion(entry)
}
weakSelf.copyToFrontStorage(key, object: object, completion: completion)
}
}
}

private func copyToFrontStorage<T: Cachable>(_ key: String, object: T, completion: @escaping (_ object: T?) -> Void) {

guard let metadata = self.backStorage.objectMetadata(key) else {
completion(nil)
return
}

self.frontStorage.add(key, object: object, expiry: metadata.expiry, completion: { _ in
completion(object)
})
}

/**
Removes the object from to the front and back cache storages.
Expand Down
11 changes: 10 additions & 1 deletion Source/Shared/Cache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,17 @@ public final class Cache<T: Cachable>: BasicHybridCache {
- Parameter key: Unique key to identify the object in the cache
- Parameter completion: Completion closure returns object or nil
*/

public func object(_ key: String, completion: @escaping (_ object: T?) -> Void) {
super.object(forKey: key, completion: completion)
}

/**
Tries to retrieve the cache entry from to the front and back cache storages.
- Parameter key: Unique key to identify the cache entry in the cache
- Parameter completion: Completion closure returns cache entry or nil
*/
public func cacheEntry(_ key: String, completion: @escaping (_ object: CacheEntry<T>?) -> Void) {
super.cacheEntry(forKey: key, completion: completion)
}
}
10 changes: 10 additions & 0 deletions Source/Shared/HybridCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,14 @@ public class HybridCache: BasicHybridCache {
public func object<T: Cachable>(_ key: String, completion: @escaping (_ object: T?) -> Void) {
super.object(forKey: key, completion: completion)
}

/**
Tries to retrieve the cache entry from to the front and back cache storages.
- Parameter key: Unique key to identify the cache entry in the cache
- Parameter completion: Completion closure returns cache entry or nil
*/
public func cacheEntry<T: Cachable>(_ key: String, completion: @escaping (_ object: CacheEntry<T>?) -> Void) {
super.cacheEntry(forKey: key, completion: completion)
}
}
4 changes: 4 additions & 0 deletions Source/Shared/Storage/CacheEntry.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public struct CacheEntry<T> {
public let object: T
public let expiry: Expiry
}
51 changes: 33 additions & 18 deletions Source/Shared/Storage/DiskStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,42 +86,57 @@ public final class DiskStorage: StorageAware {
Gets information about the cached object.
- Parameter key: Unique key to identify the object in the cache
- Parameter completion: Completion closure returns object or nil
*/
public func objectMetadata(_ key: String) -> ObjectMetadata? {

do {
let attributes = try fileManager.attributesOfItem(atPath: filePath(key))
let fileModifiedDate = Expiry.date(attributes[FileAttributeKey.modificationDate] as! Date)
return ObjectMetadata(expiry: fileModifiedDate)

} catch {}

return nil
public func object<T: Cachable>(_ key: String, completion: @escaping (_ object: T?) -> Void) {
cacheEntry(key) { entry in
completion(entry?.object)
}
}

/**
Tries to retrieve the object from the disk storage.
Get cache entry which includes object with metadata.
- Parameter key: Unique key to identify the object in the cache
- Parameter completion: Completion closure returns object or nil
- Parameter completion: Completion closure returns object wrapper with metadata or nil
*/
public func object<T: Cachable>(_ key: String, completion: @escaping (_ object: T?) -> Void) {
public func cacheEntry<T: Cachable>(_ key: String, completion: @escaping (_ object: CacheEntry<T>?) -> Void) {
readQueue.async { [weak self] in
guard let weakSelf = self else {
completion(nil)
return
}

let filePath = weakSelf.filePath(key)
var cachedObject: T?

if let data = try? Data(contentsOf: URL(fileURLWithPath: filePath)) {
cachedObject = T.decode(data) as? T
}

completion(cachedObject)

if let cachedObject = cachedObject,
let expiry = weakSelf.cachedObjectExpiry(path: filePath) {

completion(CacheEntry(object: cachedObject, expiry: expiry))
return
}

completion(nil)
}
}

private func cachedObjectExpiry(path: String) -> Expiry? {
do {
let attributes = try fileManager.attributesOfItem(atPath: path)

guard let modificationDate = attributes[FileAttributeKey.modificationDate] as? Date else {
return nil
}
return Expiry.date(modificationDate)
} catch {}

return nil
}

/**
Removes the object from the cache by the given key.
Expand Down
41 changes: 24 additions & 17 deletions Source/Shared/Storage/MemoryStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,40 +64,47 @@ public final class MemoryStorage: StorageAware {
completion?()
}
}

/**
Gets information about the cached object.
Tries to retrieve the object from the memory storage.
- Parameter key: Unique key to identify the object in the cache
- Parameter completion: Completion closure returns object or nil
*/
public func objectMetadata(_ key: String) -> ObjectMetadata? {

guard let capsule = cache.object(forKey: key as AnyObject) as? Capsule else {
return nil
public func object<T: Cachable>(_ key: String, completion: @escaping (_ object: T?) -> Void) {
cacheEntry(key) { entry in
completion(entry?.object)
}

return ObjectMetadata(expiry: Expiry.date(capsule.expiryDate))
}

/**
Tries to retrieve the object from the memory storage.
Get cache entry which includes object with metadata.
- Parameter key: Unique key to identify the object in the cache
- Parameter completion: Completion closure returns object or nil
- Parameter completion: Completion closure returns object wrapper with metadata or nil
*/
public func object<T: Cachable>(_ key: String, completion: @escaping (_ object: T?) -> Void) {
public func cacheEntry<T: Cachable>(_ key: String, completion: @escaping (_ object: CacheEntry<T>?) -> Void) {
readQueue.async { [weak self] in
guard let weakSelf = self else {
completion(nil)
return
}

let capsule = weakSelf.cache.object(forKey: key as AnyObject) as? Capsule
completion(capsule?.object as? T)

if let capsule = capsule {
weakSelf.removeIfExpired(key, capsule: capsule)

guard let capsule = weakSelf.cache.object(forKey: key as AnyObject) as? Capsule else {
completion(nil)
return
}

var entry: CacheEntry<T>?

if let object = capsule.object as? T {
entry = CacheEntry(object: object, expiry: Expiry.date(capsule.expiryDate))
}

completion(entry)

weakSelf.removeIfExpired(key, capsule: capsule)
}
}

Expand Down
9 changes: 0 additions & 9 deletions Source/Shared/Storage/ObjectMetadata.swift

This file was deleted.

5 changes: 3 additions & 2 deletions Source/Shared/Storage/StorageAware.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ public protocol CacheAware {
func add<T: Cachable>(_ key: String, object: T, expiry: Expiry, completion: (() -> Void)?)

/**
Gets information about the cached object.
Get cache entry which includes object with metadata.
- Parameter key: Unique key to identify the object in the cache
- Parameter completion: Completion closure returns object wrapper with metadata or nil
*/
func objectMetadata(_ key: String) -> ObjectMetadata?
func cacheEntry<T: Cachable>(_ key: String, completion: @escaping (_ object: CacheEntry<T>?) -> Void)

/**
Tries to retrieve the object from the cache.
Expand Down
Loading

0 comments on commit 072fd66

Please sign in to comment.