Skip to content

Commit

Permalink
Merge pull request #10 from hyperoslo/improve/memory-cache
Browse files Browse the repository at this point in the history
Improve read and write
  • Loading branch information
zenangst committed Nov 12, 2015
2 parents 5aa7964 + 2dd0ff9 commit d8cc136
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 57 deletions.
13 changes: 7 additions & 6 deletions Pod/Tests/Specs/DiskCacheSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class DiskCacheSpec: QuickSpec {
it("returns the correct path") {
let paths = NSSearchPathForDirectoriesInDomains(.CachesDirectory,
NSSearchPathDomainMask.UserDomainMask, true)
let path = "\(paths.first!)/\(cache.prefix).\(name.capitalizedString)"
let path = "\(paths.first!)/\(DiskCache.prefix).\(name.capitalizedString)"

expect(cache.path).to(equal(path))
}
Expand Down Expand Up @@ -70,11 +70,12 @@ class DiskCacheSpec: QuickSpec {
let expectation = self.expectationWithDescription(
"Object Expectation")

cache.add(key, object: object)
cache.object(key) { (receivedObject: User?) in
expect(receivedObject?.firstName).to(equal(object.firstName))
expect(receivedObject?.lastName).to(equal(object.lastName))
expectation.fulfill()
cache.add(key, object: object) {
cache.object(key) { (receivedObject: User?) in
expect(receivedObject?.firstName).to(equal(object.firstName))
expect(receivedObject?.lastName).to(equal(object.lastName))
expectation.fulfill()
}
}

self.waitForExpectationsWithTimeout(2.0, handler:nil)
Expand Down
22 changes: 12 additions & 10 deletions Pod/Tests/Specs/MemoryCacheSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class MemoryCacheSpec: QuickSpec {

describe("#path") {
it("returns the correct path") {
let path = "\(cache.prefix).\(name.capitalizedString)"
let path = "\(MemoryCache.prefix).\(name.capitalizedString)"

expect(cache.path).to(equal(path))
}
Expand All @@ -37,10 +37,11 @@ class MemoryCacheSpec: QuickSpec {
let expectation = self.expectationWithDescription(
"Save Object Expectation")

cache.add(key, object: object)
cache.object(key) { (receivedObject: User?) in
expect(receivedObject).toNot(beNil())
expectation.fulfill()
cache.add(key, object: object) {
cache.object(key) { (receivedObject: User?) in
expect(receivedObject).toNot(beNil())
expectation.fulfill()
}
}

self.waitForExpectationsWithTimeout(2.0, handler:nil)
Expand All @@ -52,11 +53,12 @@ class MemoryCacheSpec: QuickSpec {
let expectation = self.expectationWithDescription(
"Object Expectation")

cache.add(key, object: object)
cache.object(key) { (receivedObject: User?) in
expect(receivedObject?.firstName).to(equal(object.firstName))
expect(receivedObject?.lastName).to(equal(object.lastName))
expectation.fulfill()
cache.add(key, object: object) {
cache.object(key) { (receivedObject: User?) in
expect(receivedObject?.firstName).to(equal(object.firstName))
expect(receivedObject?.lastName).to(equal(object.lastName))
expectation.fulfill()
}
}

self.waitForExpectationsWithTimeout(2.0, handler:nil)
Expand Down
4 changes: 3 additions & 1 deletion Source/CacheAware.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import Foundation

public protocol CacheAware {

var prefix: String { get }
static var prefix: String { get }
var path: String { get }
var maxSize: UInt { get set }
var writeQueue: dispatch_queue_t { get }
var readQueue: dispatch_queue_t { get }

init(name: String)

Expand Down
61 changes: 30 additions & 31 deletions Source/DiskCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import Foundation

public class DiskCache: CacheAware {

public let prefix = "no.hyper.Cache.Disk"
public let ioQueueName = "no.hyper.Cache.Disk.IOQueue."
public static let prefix = "no.hyper.Cache.Disk"

public let path: String
public var maxSize: UInt = 0
public private(set) var writeQueue: dispatch_queue_t
public private(set) var readQueue: dispatch_queue_t

private var fileManager: NSFileManager!
private let ioQueue: dispatch_queue_t
private lazy var fileManager: NSFileManager = {
let fileManager = NSFileManager()
return fileManager
}()

// MARK: - Initialization

Expand All @@ -17,34 +21,35 @@ public class DiskCache: CacheAware {
let paths = NSSearchPathForDirectoriesInDomains(.CachesDirectory,
NSSearchPathDomainMask.UserDomainMask, true)

path = "\(paths.first!)/\(prefix).\(cacheName)"
ioQueue = dispatch_queue_create("\(ioQueueName).\(cacheName)", DISPATCH_QUEUE_SERIAL)

dispatch_sync(ioQueue) {
self.fileManager = NSFileManager()
}
path = "\(paths.first!)/\(DiskCache.prefix).\(cacheName)"
writeQueue = dispatch_queue_create("\(DiskCache.prefix).\(cacheName).WriteQueue",
DISPATCH_QUEUE_SERIAL)
readQueue = dispatch_queue_create("\(DiskCache.prefix).\(cacheName).ReadQueue",
DISPATCH_QUEUE_SERIAL)
}

// MARK: - CacheAware

public func add<T: Cachable>(key: String, object: T, completion: (() -> Void)? = nil) {
if !fileManager.fileExistsAtPath(path) {
do {
try fileManager.createDirectoryAtPath(path,
withIntermediateDirectories: true, attributes: nil)
} catch _ {}
}
dispatch_async(writeQueue) { [weak self] in
guard let weakSelf = self else { return }

fileManager.createFileAtPath(filePath(key),
contents: object.encode(), attributes: nil)
if !weakSelf.fileManager.fileExistsAtPath(weakSelf.path) {
do {
try weakSelf.fileManager.createDirectoryAtPath(weakSelf.path,
withIntermediateDirectories: true, attributes: nil)
} catch _ {}
}

weakSelf.fileManager.createFileAtPath(weakSelf.filePath(key),
contents: object.encode(), attributes: nil)

dispatch_async(dispatch_get_main_queue()) {
completion?()
}
}

public func object<T: Cachable>(key: String, completion: (object: T?) -> Void) {
dispatch_async(ioQueue) { [weak self] in
dispatch_async(readQueue) { [weak self] in
guard let weakSelf = self else { return }

let filePath = weakSelf.filePath(key)
Expand All @@ -53,37 +58,31 @@ public class DiskCache: CacheAware {
cachedObject = T.decode(data)
}

dispatch_async(dispatch_get_main_queue()) {
completion(object: cachedObject)
}
completion(object: cachedObject)
}
}

public func remove(key: String, completion: (() -> Void)? = nil) {
dispatch_async(ioQueue) { [weak self] in
dispatch_async(writeQueue) { [weak self] in
guard let weakSelf = self else { return }

do {
try weakSelf.fileManager.removeItemAtPath(weakSelf.filePath(key))
} catch _ {}

dispatch_async(dispatch_get_main_queue()) {
completion?()
}
completion?()
}
}

public func clear(completion: (() -> Void)? = nil) {
dispatch_async(ioQueue) { [weak self] in
dispatch_async(writeQueue) { [weak self] in
guard let weakSelf = self else { return }

do {
try weakSelf.fileManager.removeItemAtPath(weakSelf.path)
} catch _ {}

dispatch_async(dispatch_get_main_queue()) {
completion?()
}
completion?()
}
}

Expand Down
39 changes: 30 additions & 9 deletions Source/MemoryCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation

public class MemoryCache: CacheAware {

public let prefix = "no.hyper.Cache.Memory"
public static let prefix = "no.hyper.Cache.Memory"

public var path: String {
return cache.name
Expand All @@ -15,31 +15,52 @@ public class MemoryCache: CacheAware {
}

public let cache = NSCache()
public private(set) var writeQueue: dispatch_queue_t
public private(set) var readQueue: dispatch_queue_t

// MARK: - Initialization

public required init(name: String) {
cache.name = "\(prefix).\(name.capitalizedString)"
cache.name = "\(MemoryCache.prefix).\(name.capitalizedString)"
writeQueue = dispatch_queue_create("\(cache.name).WriteQueue", DISPATCH_QUEUE_SERIAL)
readQueue = dispatch_queue_create("\(cache.name).ReadQueue", DISPATCH_QUEUE_SERIAL)
}

// MARK: - CacheAware

public func add<T: Cachable>(key: String, object: T, completion: (() -> Void)? = nil) {
cache.setObject(object, forKey: key)
dispatch_async(writeQueue) { [weak self] in
guard let weakSelf = self else { return }

weakSelf.cache.setObject(object, forKey: key)
completion?()
}
}

public func object<T: Cachable>(key: String, completion: (object: T?) -> Void) {
let cachedObject = cache.objectForKey(key) as? T
completion(object: cachedObject)
dispatch_async(readQueue) { [weak self] in
guard let weakSelf = self else { return }

let cachedObject = weakSelf.cache.objectForKey(key) as? T
completion(object: cachedObject)
}
}

public func remove(key: String, completion: (() -> Void)? = nil) {
cache.removeObjectForKey(key)
completion?()
dispatch_async(writeQueue) { [weak self] in
guard let weakSelf = self else { return }

weakSelf.cache.removeObjectForKey(key)
completion?()
}
}

public func clear(completion: (() -> Void)? = nil) {
cache.removeAllObjects()
completion?()
dispatch_async(writeQueue) { [weak self] in
guard let weakSelf = self else { return }

weakSelf.cache.removeAllObjects()
completion?()
}
}
}

0 comments on commit d8cc136

Please sign in to comment.