Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions Pod/Tests/Specs/Storage/DiskStorageSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,38 @@ class DiskStorageSpec: QuickSpec {
}
}

describe("clearExpired") {
it("removes expired objects") {
let expectation1 = self.expectationWithDescription(
"Clear If Expired Expectation")
let expectation2 = self.expectationWithDescription(
"Don't Clear If Not Expired Expectation")

let expiry1: Expiry = .Date(NSDate().dateByAddingTimeInterval(-100000))
let expiry2: Expiry = .Date(NSDate().dateByAddingTimeInterval(100000))

let key1 = "item1"
let key2 = "item2"

storage.add(key1, object: object, expiry: expiry1)
storage.add(key2, object: object, expiry: expiry2)

storage.clearExpired {
storage.object(key1) { (receivedObject: User?) in
expect(receivedObject).to(beNil())
expectation1.fulfill()
}

storage.object(key2) { (receivedObject: User?) in
expect(receivedObject).toNot(beNil())
expectation2.fulfill()
}
}

self.waitForExpectationsWithTimeout(5.0, handler:nil)
}
}

describe("#fileName") {
it("returns a correct file name") {
expect(storage.fileName(key)).to(equal(key.base64()))
Expand Down
32 changes: 32 additions & 0 deletions Pod/Tests/Specs/Storage/MemoryStorageSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,38 @@ class MemoryStorageSpec: QuickSpec {
self.waitForExpectationsWithTimeout(2.0, handler:nil)
}
}

describe("clearExpired") {
it("removes expired objects") {
let expectation1 = self.expectationWithDescription(
"Clear Expired Expectation 1")
let expectation2 = self.expectationWithDescription(
"Clear Expired Expectation 2")

let expiry1: Expiry = .Date(NSDate().dateByAddingTimeInterval(-100000))
let expiry2: Expiry = .Date(NSDate().dateByAddingTimeInterval(100000))

let key1 = "item1"
let key2 = "item2"

storage.add(key1, object: object, expiry: expiry1)
storage.add(key2, object: object, expiry: expiry2)

storage.clearExpired {
storage.object(key1) { (receivedObject: User?) in
expect(receivedObject).to(beNil())
expectation1.fulfill()
}

storage.object(key2) { (receivedObject: User?) in
expect(receivedObject).to(beNil())
expectation2.fulfill()
}
}

self.waitForExpectationsWithTimeout(5.0, handler:nil)
}
}
}
}
}
49 changes: 48 additions & 1 deletion Source/Cache/HybridCache.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Foundation
import UIKit

public class HybridCache {

Expand All @@ -16,6 +16,19 @@ public class HybridCache {

frontStorage = StorageFactory.resolve(name, kind: config.frontKind, maxSize: config.maxSize)
backStorage = StorageFactory.resolve(name, kind: config.backKind, maxSize: config.maxSize)

let notificationCenter = NSNotificationCenter.defaultCenter()

notificationCenter.addObserver(self, selector: "applicationDidReceiveMemoryWarning",
name: UIApplicationDidReceiveMemoryWarningNotification, object: nil)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️

notificationCenter.addObserver(self, selector: "applicationWillTerminate",
name: UIApplicationWillTerminateNotification, object: nil)
Copy link
Contributor

Choose a reason for hiding this comment

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

💀

notificationCenter.addObserver(self, selector: "applicationDidEnterBackground",
name: UIApplicationDidEnterBackgroundNotification, object: nil)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to remove these notifications at any time?

}

deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}

// MARK: - Caching
Expand Down Expand Up @@ -78,4 +91,38 @@ public class HybridCache {
}
}
}

// MARK: - Notifications

func applicationDidReceiveMemoryWarning() {
frontStorage.clearExpired(nil)
}

func applicationWillTerminate() {
backStorage.clearExpired(nil)
}

func applicationDidEnterBackground() {
let application = UIApplication.sharedApplication()
var backgroundTask: UIBackgroundTaskIdentifier?

backgroundTask = application.beginBackgroundTaskWithExpirationHandler { [weak self] in
guard let weakSelf = self, var backgroundTask = backgroundTask else { return }

weakSelf.endBackgroundTask(&backgroundTask)
}

backStorage.clearExpired { [weak self] in
guard let weakSelf = self, var backgroundTask = backgroundTask else { return }

dispatch_async(dispatch_get_main_queue()) {
weakSelf.endBackgroundTask(&backgroundTask)
}
}
}

func endBackgroundTask(inout task: UIBackgroundTaskIdentifier) {
UIApplication.sharedApplication().endBackgroundTask(task)
task = UIBackgroundTaskInvalid
}
}
84 changes: 79 additions & 5 deletions Source/Storage/DiskStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class DiskStorage: StorageAware {
do {
try weakSelf.fileManager.createDirectoryAtPath(weakSelf.path,
withIntermediateDirectories: true, attributes: nil)
} catch _ {}
} catch {}
}

do {
Expand All @@ -52,7 +52,7 @@ public class DiskStorage: StorageAware {
try weakSelf.fileManager.setAttributes(
[NSFileModificationDate : expiry.date],
ofItemAtPath: filePath)
} catch _ {}
} catch {}

completion?()
}
Expand Down Expand Up @@ -85,7 +85,7 @@ public class DiskStorage: StorageAware {

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

completion?()
}
Expand All @@ -106,7 +106,7 @@ public class DiskStorage: StorageAware {
where expiryDate.inThePast {
try weakSelf.fileManager.removeItemAtPath(weakSelf.filePath(key))
}
} catch _ {}
} catch {}

completion?()
}
Expand All @@ -121,7 +121,81 @@ public class DiskStorage: StorageAware {

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

completion?()
}
}

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

let URL = NSURL(fileURLWithPath: weakSelf.path)
let resourceKeys = [NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey]
var objects = [(URL: NSURL, resourceValues: [NSObject: AnyObject])]()
var URLsToDelete = [NSURL]()
var totalSize: UInt = 0

guard let fileEnumerator = weakSelf.fileManager.enumeratorAtURL(URL, includingPropertiesForKeys: resourceKeys,
options: .SkipsHiddenFiles, errorHandler: nil), URLs = fileEnumerator.allObjects as? [NSURL] else {
completion?()
return
}

for fileURL in URLs {
do {
let resourceValues = try fileURL.resourceValuesForKeys(resourceKeys)

guard (resourceValues[NSURLIsDirectoryKey] as? NSNumber)?.boolValue == false else {
continue
}

if let expiryDate = resourceValues[NSURLContentModificationDateKey] as? NSDate
where expiryDate.inThePast {
URLsToDelete.append(fileURL)
continue
}

if let fileSize = resourceValues[NSURLTotalFileAllocatedSizeKey] as? NSNumber {
totalSize += fileSize.unsignedLongValue
objects.append((URL: fileURL, resourceValues: resourceValues))
}
} catch {}
}

for fileURL in URLsToDelete {
do {
try weakSelf.fileManager.removeItemAtURL(fileURL)
} catch {}
}

if weakSelf.maxSize > 0 && totalSize > weakSelf.maxSize {
let targetSize = weakSelf.maxSize / 2

let sortedFiles = objects.sort {
let time1 = ($0.resourceValues[NSURLContentModificationDateKey] as? NSDate)?.timeIntervalSince1970
let time2 = ($1.resourceValues[NSURLContentModificationDateKey] as? NSDate)?.timeIntervalSince1970
return time1 > time2
}

for file in sortedFiles {
do {
try weakSelf.fileManager.removeItemAtURL(file.URL)
} catch {}

if let fileSize = file.resourceValues[NSURLTotalFileAllocatedSizeKey] as? NSNumber {
totalSize -= fileSize.unsignedLongValue
}

if totalSize < targetSize {
break
}
}
}

completion?()
}
Expand Down
6 changes: 5 additions & 1 deletion Source/Storage/MemoryStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ public class MemoryStorage: StorageAware {
}
}

public func clearExpired(completion: (() -> Void)? = nil) {
clear(completion)
}

// MARK: - Helpers

func removeIfExpired(key: String, capsule: Capsule, completion: (() -> Void)? = nil) {
Expand All @@ -107,4 +111,4 @@ public class MemoryStorage: StorageAware {
completion?()
}
}
}
}
1 change: 1 addition & 0 deletions Source/Storage/StorageAware.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public protocol CacheAware {
func remove(key: String, completion: (() -> Void)?)
func removeIfExpired(key: String, completion: (() -> Void)?)
func clear(completion: (() -> Void)?)
func clearExpired(completion: (() -> Void)?)
}

public protocol StorageAware: CacheAware {
Expand Down