mirror of
https://github.com/samsonjs/CacheCreek.git
synced 2026-04-27 15:07:39 +00:00
convert tabs to spaces
This commit is contained in:
parent
137bb3fac0
commit
fe4dc9a69a
3 changed files with 297 additions and 297 deletions
|
|
@ -14,247 +14,247 @@ class CacheCreekTests: XCTestCase {
|
||||||
typealias Node = DoublyLinkedListNode
|
typealias Node = DoublyLinkedListNode
|
||||||
|
|
||||||
func testSettingAndGettingItems() {
|
func testSettingAndGettingItems() {
|
||||||
let cache = LRUCache()
|
let cache = LRUCache()
|
||||||
cache.set(item: 123, forKey: "123")
|
cache.set(item: 123, forKey: "123")
|
||||||
|
|
||||||
XCTAssert(cache.count == 1)
|
XCTAssert(cache.count == 1)
|
||||||
XCTAssert(cache.item(forKey: "123") == 123)
|
XCTAssert(cache.item(forKey: "123") == 123)
|
||||||
XCTAssert(cache[123] == nil)
|
XCTAssert(cache[123] == nil)
|
||||||
|
|
||||||
cache[234] = "234"
|
cache[234] = "234"
|
||||||
|
|
||||||
XCTAssert(cache.count == 2)
|
XCTAssert(cache.count == 2)
|
||||||
XCTAssert(cache.item(forKey: 234) == "234")
|
XCTAssert(cache.item(forKey: 234) == "234")
|
||||||
|
|
||||||
// Test setting/getting an array
|
// Test setting/getting an array
|
||||||
let array = [1, 2, 3, 4, 5]
|
let array = [1, 2, 3, 4, 5]
|
||||||
cache[5] = array
|
cache[5] = array
|
||||||
|
|
||||||
XCTAssert(cache.count == 3)
|
XCTAssert(cache.count == 3)
|
||||||
if let fetchedArray: [Int] = cache.item(forKey: 5) {
|
if let fetchedArray: [Int] = cache.item(forKey: 5) {
|
||||||
XCTAssert(fetchedArray == array)
|
XCTAssert(fetchedArray == array)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
XCTFail("Expected an int array")
|
XCTFail("Expected an int array")
|
||||||
}
|
}
|
||||||
|
|
||||||
let testStruct = TestStruct(name: "Testing", value: Int(arc4random_uniform(100000)))
|
let testStruct = TestStruct(name: "Testing", value: Int(arc4random_uniform(100000)))
|
||||||
cache["TestingStruct"] = testStruct
|
cache["TestingStruct"] = testStruct
|
||||||
|
|
||||||
guard let fetchedStruct: TestStruct = cache.item(forKey: "TestingStruct") else {
|
guard let fetchedStruct: TestStruct = cache.item(forKey: "TestingStruct") else {
|
||||||
XCTFail()
|
XCTFail()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
XCTAssert(testStruct.name == fetchedStruct.name)
|
XCTAssert(testStruct.name == fetchedStruct.name)
|
||||||
XCTAssert(testStruct.value == fetchedStruct.value)
|
XCTAssert(testStruct.value == fetchedStruct.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDifferentKindsOfKeys() {
|
func testDifferentKindsOfKeys() {
|
||||||
let cache = LRUCache()
|
let cache = LRUCache()
|
||||||
|
|
||||||
let floatKey: Float = 123.456
|
let floatKey: Float = 123.456
|
||||||
cache.set(item: 123.456, forKey: floatKey)
|
cache.set(item: 123.456, forKey: floatKey)
|
||||||
XCTAssert(cache.item(forKey: floatKey) as Double? == .Some(123.456))
|
XCTAssert(cache.item(forKey: floatKey) as Double? == .Some(123.456))
|
||||||
|
|
||||||
cache[floatKey] = 456.789
|
cache[floatKey] = 456.789
|
||||||
XCTAssert(cache.count == 1)
|
XCTAssert(cache.count == 1)
|
||||||
XCTAssert(cache[floatKey] as? Double == .Some(456.789))
|
XCTAssert(cache[floatKey] as? Double == .Some(456.789))
|
||||||
|
|
||||||
cache.set(item: "123.456", forKey: "123.456")
|
cache.set(item: "123.456", forKey: "123.456")
|
||||||
XCTAssert(cache.count == 2)
|
XCTAssert(cache.count == 2)
|
||||||
XCTAssert(cache.item(forKey: "123.456") as String? == .Some("123.456"))
|
XCTAssert(cache.item(forKey: "123.456") as String? == .Some("123.456"))
|
||||||
|
|
||||||
let boolKey = true
|
let boolKey = true
|
||||||
cache.set(item: true, forKey: boolKey)
|
cache.set(item: true, forKey: boolKey)
|
||||||
XCTAssert(cache.count == 3)
|
XCTAssert(cache.count == 3)
|
||||||
XCTAssert(cache.item(forKey: boolKey) as Bool? == .Some(true))
|
XCTAssert(cache.item(forKey: boolKey) as Bool? == .Some(true))
|
||||||
|
|
||||||
cache.removeItem(forKey: boolKey)
|
cache.removeItem(forKey: boolKey)
|
||||||
XCTAssert(cache.count == 2)
|
XCTAssert(cache.count == 2)
|
||||||
XCTAssert(cache.item(forKey: boolKey) as Bool? == .None)
|
XCTAssert(cache.item(forKey: boolKey) as Bool? == .None)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSettingAndGettingEnum() {
|
func testSettingAndGettingEnum() {
|
||||||
let cache = LRUCache()
|
let cache = LRUCache()
|
||||||
cache["ABC"] = TestEnum.ABC
|
cache["ABC"] = TestEnum.ABC
|
||||||
cache["DEF"] = TestEnum.DEF("BlahBlahBlah")
|
cache["DEF"] = TestEnum.DEF("BlahBlahBlah")
|
||||||
cache["GHI"] = TestEnum.GHI(-500)
|
cache["GHI"] = TestEnum.GHI(-500)
|
||||||
|
|
||||||
guard let abc: TestEnum = cache.item(forKey: "ABC"),
|
guard let abc: TestEnum = cache.item(forKey: "ABC"),
|
||||||
def: TestEnum = cache.item(forKey: "DEF"),
|
def: TestEnum = cache.item(forKey: "DEF"),
|
||||||
ghi: TestEnum = cache.item(forKey: "GHI")
|
ghi: TestEnum = cache.item(forKey: "GHI")
|
||||||
else {
|
else {
|
||||||
XCTFail()
|
XCTFail()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch (abc, def, ghi) {
|
switch (abc, def, ghi) {
|
||||||
case (.ABC, .DEF(let stringValue), .GHI(let intValue)):
|
case (.ABC, .DEF(let stringValue), .GHI(let intValue)):
|
||||||
XCTAssert(stringValue == "BlahBlahBlah")
|
XCTAssert(stringValue == "BlahBlahBlah")
|
||||||
XCTAssert(intValue == -500)
|
XCTAssert(intValue == -500)
|
||||||
default:
|
default:
|
||||||
XCTFail()
|
XCTFail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSubscripts() {
|
func testSubscripts() {
|
||||||
let cache = LRUCache()
|
let cache = LRUCache()
|
||||||
|
|
||||||
// Int subscript
|
// Int subscript
|
||||||
cache[123] = 123
|
cache[123] = 123
|
||||||
XCTAssert(cache[123] as? Int == .Some(123))
|
XCTAssert(cache[123] as? Int == .Some(123))
|
||||||
XCTAssert(cache.count == 1)
|
XCTAssert(cache.count == 1)
|
||||||
|
|
||||||
cache[123] = nil
|
cache[123] = nil
|
||||||
XCTAssert(cache[123] as? Int == .None)
|
XCTAssert(cache[123] as? Int == .None)
|
||||||
XCTAssert(cache.count == 0)
|
XCTAssert(cache.count == 0)
|
||||||
|
|
||||||
// String subscript
|
// String subscript
|
||||||
cache["123"] = 123
|
cache["123"] = 123
|
||||||
XCTAssert(cache["123"] as? Int == .Some(123))
|
XCTAssert(cache["123"] as? Int == .Some(123))
|
||||||
XCTAssert(cache.count == 1)
|
XCTAssert(cache.count == 1)
|
||||||
|
|
||||||
cache["123"] = nil
|
cache["123"] = nil
|
||||||
XCTAssert(cache["123"] as? Int == .None)
|
XCTAssert(cache["123"] as? Int == .None)
|
||||||
XCTAssert(cache.count == 0)
|
XCTAssert(cache.count == 0)
|
||||||
|
|
||||||
// Float subscript
|
// Float subscript
|
||||||
let floatKey: Float = 3.14
|
let floatKey: Float = 3.14
|
||||||
cache[floatKey] = 123
|
cache[floatKey] = 123
|
||||||
XCTAssert(cache[floatKey] as? Int == .Some(123))
|
XCTAssert(cache[floatKey] as? Int == .Some(123))
|
||||||
XCTAssert(cache.count == 1)
|
XCTAssert(cache.count == 1)
|
||||||
|
|
||||||
cache[floatKey] = nil
|
cache[floatKey] = nil
|
||||||
XCTAssert(cache[floatKey] as? Int == .None)
|
XCTAssert(cache[floatKey] as? Int == .None)
|
||||||
XCTAssert(cache.count == 0)
|
XCTAssert(cache.count == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRemovingItems() {
|
func testRemovingItems() {
|
||||||
let cache = LRUCache()
|
let cache = LRUCache()
|
||||||
cache.set(item: 123, forKey: 123)
|
cache.set(item: 123, forKey: 123)
|
||||||
cache.set(item: 234, forKey: 234)
|
cache.set(item: 234, forKey: 234)
|
||||||
cache.set(item: 345, forKey: 345)
|
cache.set(item: 345, forKey: 345)
|
||||||
cache.set(item: 456, forKey: 456)
|
cache.set(item: 456, forKey: 456)
|
||||||
|
|
||||||
XCTAssert(cache.count == 4)
|
XCTAssert(cache.count == 4)
|
||||||
|
|
||||||
cache.removeItem(forKey: 123)
|
cache.removeItem(forKey: 123)
|
||||||
|
|
||||||
XCTAssert(cache.count == 3)
|
XCTAssert(cache.count == 3)
|
||||||
XCTAssert(cache[123] == nil)
|
XCTAssert(cache[123] == nil)
|
||||||
|
|
||||||
cache[234] = nil
|
cache[234] = nil
|
||||||
|
|
||||||
XCTAssert(cache.count == 2)
|
XCTAssert(cache.count == 2)
|
||||||
XCTAssert(cache[234] == nil)
|
XCTAssert(cache[234] == nil)
|
||||||
|
|
||||||
cache.removeAllItems()
|
cache.removeAllItems()
|
||||||
|
|
||||||
XCTAssert(cache.count == 0)
|
XCTAssert(cache.count == 0)
|
||||||
|
|
||||||
cache.set(item: 123, forKey: 123)
|
cache.set(item: 123, forKey: 123)
|
||||||
cache.set(item: 234, forKey: 234)
|
cache.set(item: 234, forKey: 234)
|
||||||
cache.set(item: 345, forKey: 345)
|
cache.set(item: 345, forKey: 345)
|
||||||
cache.set(item: 456, forKey: 456)
|
cache.set(item: 456, forKey: 456)
|
||||||
|
|
||||||
XCTAssert(cache.count == 4)
|
XCTAssert(cache.count == 4)
|
||||||
|
|
||||||
NSNotificationCenter.defaultCenter().postNotificationName(UIApplicationDidReceiveMemoryWarningNotification, object: UIApplication.sharedApplication())
|
NSNotificationCenter.defaultCenter().postNotificationName(UIApplicationDidReceiveMemoryWarningNotification, object: UIApplication.sharedApplication())
|
||||||
|
|
||||||
XCTAssert(cache.count == 0)
|
XCTAssert(cache.count == 0)
|
||||||
|
|
||||||
cache.set(item: 123, forKey: 123)
|
cache.set(item: 123, forKey: 123)
|
||||||
cache.set(item: 234, forKey: 234)
|
cache.set(item: 234, forKey: 234)
|
||||||
cache.set(item: 345, forKey: 345)
|
cache.set(item: 345, forKey: 345)
|
||||||
cache.set(item: 456, forKey: 456)
|
cache.set(item: 456, forKey: 456)
|
||||||
|
|
||||||
XCTAssert(cache.count == 4)
|
XCTAssert(cache.count == 4)
|
||||||
|
|
||||||
NSNotificationCenter.defaultCenter().postNotificationName(UIApplicationDidEnterBackgroundNotification, object: UIApplication.sharedApplication())
|
NSNotificationCenter.defaultCenter().postNotificationName(UIApplicationDidEnterBackgroundNotification, object: UIApplication.sharedApplication())
|
||||||
|
|
||||||
XCTAssert(cache.count == 0)
|
XCTAssert(cache.count == 0)
|
||||||
|
|
||||||
cache.set(item: 123, forKey: 123)
|
cache.set(item: 123, forKey: 123)
|
||||||
cache.set(item: 234, forKey: 234)
|
cache.set(item: 234, forKey: 234)
|
||||||
cache.set(item: 345, forKey: 345)
|
cache.set(item: 345, forKey: 345)
|
||||||
cache.set(item: 456, forKey: 456)
|
cache.set(item: 456, forKey: 456)
|
||||||
|
|
||||||
XCTAssert(cache.count == 4)
|
XCTAssert(cache.count == 4)
|
||||||
|
|
||||||
// Make sure an unknown key doesn't have any weird side effects
|
// Make sure an unknown key doesn't have any weird side effects
|
||||||
cache[567] = nil
|
cache[567] = nil
|
||||||
|
|
||||||
XCTAssert(cache.count == 4)
|
XCTAssert(cache.count == 4)
|
||||||
|
|
||||||
cache.removeItem(forKey: 999)
|
cache.removeItem(forKey: 999)
|
||||||
|
|
||||||
XCTAssert(cache.count == 4)
|
XCTAssert(cache.count == 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCountLimit() {
|
func testCountLimit() {
|
||||||
let cache = LRUCache()
|
let cache = LRUCache()
|
||||||
cache.set(item: 123, forKey: 123)
|
cache.set(item: 123, forKey: 123)
|
||||||
cache.set(item: 234, forKey: 234)
|
cache.set(item: 234, forKey: 234)
|
||||||
cache.set(item: 345, forKey: 345)
|
cache.set(item: 345, forKey: 345)
|
||||||
cache.set(item: 456, forKey: 456)
|
cache.set(item: 456, forKey: 456)
|
||||||
|
|
||||||
XCTAssert(cache.count == 4)
|
XCTAssert(cache.count == 4)
|
||||||
|
|
||||||
cache.countLimit = 3
|
cache.countLimit = 3
|
||||||
|
|
||||||
XCTAssert(cache.count == 3)
|
XCTAssert(cache.count == 3)
|
||||||
|
|
||||||
cache.removeAllItems()
|
cache.removeAllItems()
|
||||||
|
|
||||||
XCTAssert(cache.count == 0)
|
XCTAssert(cache.count == 0)
|
||||||
|
|
||||||
cache.set(item: 123, forKey: 123)
|
cache.set(item: 123, forKey: 123)
|
||||||
cache.set(item: 234, forKey: 234)
|
cache.set(item: 234, forKey: 234)
|
||||||
cache.set(item: 345, forKey: 345)
|
cache.set(item: 345, forKey: 345)
|
||||||
cache.set(item: 456, forKey: 456)
|
cache.set(item: 456, forKey: 456)
|
||||||
|
|
||||||
XCTAssert(cache.count == 3)
|
XCTAssert(cache.count == 3)
|
||||||
|
|
||||||
cache[567] = 567
|
cache[567] = 567
|
||||||
XCTAssert(cache.count == 3)
|
XCTAssert(cache.count == 3)
|
||||||
|
|
||||||
cache.removeAllItems()
|
cache.removeAllItems()
|
||||||
|
|
||||||
cache.set(item: 123, forKey: 123)
|
cache.set(item: 123, forKey: 123)
|
||||||
cache.set(item: 234, forKey: 234)
|
cache.set(item: 234, forKey: 234)
|
||||||
cache.set(item: 345, forKey: 345)
|
cache.set(item: 345, forKey: 345)
|
||||||
cache.set(item: 456, forKey: 456)
|
cache.set(item: 456, forKey: 456)
|
||||||
|
|
||||||
cache.countLimit = 2
|
cache.countLimit = 2
|
||||||
|
|
||||||
XCTAssert(cache.count == 2)
|
XCTAssert(cache.count == 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testEmptyEviction() {
|
func testEmptyEviction() {
|
||||||
// Make sure that an eviction on an empty dictionary doesn't crash
|
// Make sure that an eviction on an empty dictionary doesn't crash
|
||||||
let cache = LRUCache()
|
let cache = LRUCache()
|
||||||
cache.evictItems()
|
cache.evictItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testObjCObjects() {
|
func testObjCObjects() {
|
||||||
let cache = LRUCache()
|
let cache = LRUCache()
|
||||||
|
|
||||||
let oldCache = NSCache()
|
let oldCache = NSCache()
|
||||||
cache.set(item: oldCache, forKey: "InceptionCache")
|
cache.set(item: oldCache, forKey: "InceptionCache")
|
||||||
|
|
||||||
guard let _: NSCache = cache.item(forKey: "InceptionCache") else {
|
guard let _: NSCache = cache.item(forKey: "InceptionCache") else {
|
||||||
XCTFail("Expected an NSCache object")
|
XCTFail("Expected an NSCache object")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct TestStruct {
|
private struct TestStruct {
|
||||||
let name: String
|
let name: String
|
||||||
let value: Int
|
let value: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum TestEnum {
|
private enum TestEnum {
|
||||||
case ABC
|
case ABC
|
||||||
case DEF(String)
|
case DEF(String)
|
||||||
case GHI(Int)
|
case GHI(Int)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,33 +13,33 @@ import Foundation
|
||||||
///
|
///
|
||||||
/// `AnyKey` is a simple struct that conforms to `Hashable` to allow any other `Hashable` key to be used in the cache dictionary
|
/// `AnyKey` is a simple struct that conforms to `Hashable` to allow any other `Hashable` key to be used in the cache dictionary
|
||||||
struct AnyKey: Hashable {
|
struct AnyKey: Hashable {
|
||||||
/// The underlying value
|
/// The underlying value
|
||||||
private let underlying: Any
|
private let underlying: Any
|
||||||
/// The hashing function
|
/// The hashing function
|
||||||
private let hashValueFunc: () -> Int
|
private let hashValueFunc: () -> Int
|
||||||
/// The equality function
|
/// The equality function
|
||||||
private let equalityFunc: (Any) -> Bool
|
private let equalityFunc: (Any) -> Bool
|
||||||
|
|
||||||
init<T: Hashable>(_ key: T) {
|
init<T: Hashable>(_ key: T) {
|
||||||
underlying = key
|
underlying = key
|
||||||
// Capture the key's hashability and equatability using closures.
|
// Capture the key's hashability and equatability using closures.
|
||||||
// The Key shares the hash of the underlying value.
|
// The Key shares the hash of the underlying value.
|
||||||
hashValueFunc = { key.hashValue }
|
hashValueFunc = { key.hashValue }
|
||||||
|
|
||||||
// The Key is equal to a Key of the same underlying type,
|
// The Key is equal to a Key of the same underlying type,
|
||||||
// whose underlying value is "==" to ours.
|
// whose underlying value is "==" to ours.
|
||||||
equalityFunc = {
|
equalityFunc = {
|
||||||
if let other = $0 as? T {
|
if let other = $0 as? T {
|
||||||
return key == other
|
return key == other
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `Hashable` protocol conformance
|
/// `Hashable` protocol conformance
|
||||||
var hashValue: Int { return hashValueFunc() }
|
var hashValue: Int { return hashValueFunc() }
|
||||||
}
|
}
|
||||||
|
|
||||||
func ==(x: AnyKey, y: AnyKey) -> Bool {
|
func ==(x: AnyKey, y: AnyKey) -> Bool {
|
||||||
return x.equalityFunc(y.underlying)
|
return x.equalityFunc(y.underlying)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,167 +13,167 @@ import Foundation
|
||||||
/// It is designed to work similar to the `NSCache`, but with native Swift support.
|
/// It is designed to work similar to the `NSCache`, but with native Swift support.
|
||||||
///
|
///
|
||||||
public class LRUCache {
|
public class LRUCache {
|
||||||
// MARK: - Private variables
|
// MARK: - Private variables
|
||||||
/// An array of `NSNotificationCenter` observers that need to be removed upon deinitialization
|
/// An array of `NSNotificationCenter` observers that need to be removed upon deinitialization
|
||||||
private var notificationObservers: [NSObjectProtocol] = []
|
private var notificationObservers: [NSObjectProtocol] = []
|
||||||
|
|
||||||
/// The list of cached items. Most recently used item at head, least recently used item at tail.
|
/// The list of cached items. Most recently used item at head, least recently used item at tail.
|
||||||
private var items: DoublyLinkedList = DoublyLinkedList()
|
private var items: DoublyLinkedList = DoublyLinkedList()
|
||||||
|
|
||||||
/// Maps keys of cached items to nodes in the linked list.
|
/// Maps keys of cached items to nodes in the linked list.
|
||||||
private var keyToNodeMap: [AnyKey:DoublyLinkedListNode] = [:]
|
private var keyToNodeMap: [AnyKey:DoublyLinkedListNode] = [:]
|
||||||
|
|
||||||
// MARK: - Public variables
|
// MARK: - Public variables
|
||||||
/// The number of items in the cache.
|
/// The number of items in the cache.
|
||||||
public var count: Int {
|
public var count: Int {
|
||||||
return items.count
|
return items.count
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The limit of the amount of items that can be held in the cache. This defaults to 0, which means there is no limit.
|
/// The limit of the amount of items that can be held in the cache. This defaults to 0, which means there is no limit.
|
||||||
public var countLimit: Int = 0 {
|
public var countLimit: Int = 0 {
|
||||||
didSet {
|
didSet {
|
||||||
assert(countLimit >= 0)
|
assert(countLimit >= 0)
|
||||||
evictItems()
|
evictItems()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Initialization methods
|
// MARK: - Initialization methods
|
||||||
public init() {
|
public init() {
|
||||||
let removalBlock = { [unowned self] (_: NSNotification) in
|
let removalBlock = { [unowned self] (_: NSNotification) in
|
||||||
self.removeAllItems()
|
self.removeAllItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
var notificationObserver = NSNotificationCenter.defaultCenter()
|
var notificationObserver = NSNotificationCenter.defaultCenter()
|
||||||
.addObserverForName(UIApplicationDidReceiveMemoryWarningNotification,
|
.addObserverForName(UIApplicationDidReceiveMemoryWarningNotification,
|
||||||
object: UIApplication.sharedApplication(),
|
object: UIApplication.sharedApplication(),
|
||||||
queue: nil,
|
queue: nil,
|
||||||
usingBlock: removalBlock)
|
usingBlock: removalBlock)
|
||||||
notificationObservers.append(notificationObserver)
|
notificationObservers.append(notificationObserver)
|
||||||
notificationObserver = NSNotificationCenter.defaultCenter()
|
notificationObserver = NSNotificationCenter.defaultCenter()
|
||||||
.addObserverForName(UIApplicationDidEnterBackgroundNotification,
|
.addObserverForName(UIApplicationDidEnterBackgroundNotification,
|
||||||
object: UIApplication.sharedApplication(),
|
object: UIApplication.sharedApplication(),
|
||||||
queue: nil,
|
queue: nil,
|
||||||
usingBlock: removalBlock)
|
usingBlock: removalBlock)
|
||||||
notificationObservers.append(notificationObserver)
|
notificationObservers.append(notificationObserver)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
notificationObservers.forEach {
|
notificationObservers.forEach {
|
||||||
NSNotificationCenter.defaultCenter().removeObserver($0)
|
NSNotificationCenter.defaultCenter().removeObserver($0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Internal methods
|
// MARK: - Internal methods
|
||||||
/// Evicts items if the `countLimit` has been reached.
|
/// Evicts items if the `countLimit` has been reached.
|
||||||
///
|
///
|
||||||
func evictItems() {
|
func evictItems() {
|
||||||
guard countLimit > 0 else { return }
|
guard countLimit > 0 else { return }
|
||||||
while items.count > countLimit {
|
while items.count > countLimit {
|
||||||
if let node = items.removeLast() {
|
if let node = items.removeLast() {
|
||||||
keyToNodeMap[node.key] = nil
|
keyToNodeMap[node.key] = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Public methods
|
// MARK: - Public methods
|
||||||
/// Adds an item to the cache for any given `Hashable` key.
|
/// Adds an item to the cache for any given `Hashable` key.
|
||||||
///
|
///
|
||||||
/// - parameter item: The item to be cached
|
/// - parameter item: The item to be cached
|
||||||
/// - parameter key: The key with which to cache the item
|
/// - parameter key: The key with which to cache the item
|
||||||
///
|
///
|
||||||
public func set<K: Hashable>(item item: Any, forKey key: K) {
|
public func set<K: Hashable>(item item: Any, forKey key: K) {
|
||||||
let key = AnyKey(key)
|
let key = AnyKey(key)
|
||||||
if let existingNode = keyToNodeMap[key] {
|
if let existingNode = keyToNodeMap[key] {
|
||||||
items.remove(node: existingNode)
|
items.remove(node: existingNode)
|
||||||
}
|
}
|
||||||
let node = items.prepend(key: key, value: item)
|
let node = items.prepend(key: key, value: item)
|
||||||
keyToNodeMap[key] = node
|
keyToNodeMap[key] = node
|
||||||
evictItems()
|
evictItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an item from the cache if it exists for a given `Hashable` key.
|
/// Gets an item from the cache if it exists for a given `Hashable` key.
|
||||||
/// This method uses generics to infer the type that should be returned.
|
/// This method uses generics to infer the type that should be returned.
|
||||||
///
|
///
|
||||||
/// Note: Even if an item exists for the key, but does not match the given type, it will return `nil`.
|
/// Note: Even if an item exists for the key, but does not match the given type, it will return `nil`.
|
||||||
///
|
///
|
||||||
/// - parameter key: The key whose item should be fetched
|
/// - parameter key: The key whose item should be fetched
|
||||||
/// - returns: The item from the cache if it exists, or `nil` if an item could not be found
|
/// - returns: The item from the cache if it exists, or `nil` if an item could not be found
|
||||||
///
|
///
|
||||||
public func item<T, K: Hashable>(forKey key: K) -> T? {
|
public func item<T, K: Hashable>(forKey key: K) -> T? {
|
||||||
let key = AnyKey(key)
|
let key = AnyKey(key)
|
||||||
if let node = keyToNodeMap[key], let item = node.value as? T {
|
if let node = keyToNodeMap[key], let item = node.value as? T {
|
||||||
items.moveToHead(node: node)
|
items.moveToHead(node: node)
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Discards an item for a given `Hashable` key.
|
/// Discards an item for a given `Hashable` key.
|
||||||
///
|
///
|
||||||
/// - parameter key: The key whose item should be removed
|
/// - parameter key: The key whose item should be removed
|
||||||
///
|
///
|
||||||
public func removeItem<K: Hashable>(forKey key: K) {
|
public func removeItem<K: Hashable>(forKey key: K) {
|
||||||
let key = AnyKey(key)
|
let key = AnyKey(key)
|
||||||
if let node = keyToNodeMap[key] {
|
if let node = keyToNodeMap[key] {
|
||||||
items.remove(node: node)
|
items.remove(node: node)
|
||||||
keyToNodeMap[key] = nil
|
keyToNodeMap[key] = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clears the entire cache.
|
/// Clears the entire cache.
|
||||||
///
|
///
|
||||||
public func removeAllItems() {
|
public func removeAllItems() {
|
||||||
items.removeAll()
|
items.removeAll()
|
||||||
keyToNodeMap.removeAll()
|
keyToNodeMap.removeAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Subscript methods
|
// MARK: - Subscript methods
|
||||||
// TODO: Consolidate these subscript methods once subscript generics with constraints are supported
|
// TODO: Consolidate these subscript methods once subscript generics with constraints are supported
|
||||||
/// A subscript method that allows `Int` key subscripts.
|
/// A subscript method that allows `Int` key subscripts.
|
||||||
///
|
///
|
||||||
public subscript(key: Int) -> Any? {
|
public subscript(key: Int) -> Any? {
|
||||||
get {
|
get {
|
||||||
return item(forKey: key)
|
return item(forKey: key)
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
if let newValue = newValue {
|
if let newValue = newValue {
|
||||||
set(item: newValue, forKey: key)
|
set(item: newValue, forKey: key)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
removeItem(forKey: key)
|
removeItem(forKey: key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A subscript method that allows `Float` key subscripts.
|
/// A subscript method that allows `Float` key subscripts.
|
||||||
///
|
///
|
||||||
public subscript(key: Float) -> Any? {
|
public subscript(key: Float) -> Any? {
|
||||||
get {
|
get {
|
||||||
return item(forKey: key)
|
return item(forKey: key)
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
if let newValue = newValue {
|
if let newValue = newValue {
|
||||||
set(item: newValue, forKey: key)
|
set(item: newValue, forKey: key)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
removeItem(forKey: key)
|
removeItem(forKey: key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A subscript method that allows `String` key subscripts.
|
/// A subscript method that allows `String` key subscripts.
|
||||||
///
|
///
|
||||||
public subscript(key: String) -> Any? {
|
public subscript(key: String) -> Any? {
|
||||||
get {
|
get {
|
||||||
return item(forKey: key)
|
return item(forKey: key)
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
if let newValue = newValue {
|
if let newValue = newValue {
|
||||||
set(item: newValue, forKey: key)
|
set(item: newValue, forKey: key)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
removeItem(forKey: key)
|
removeItem(forKey: key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue