From b6545dcc0926ab95cc0fb7a3194ba40ad906e438 Mon Sep 17 00:00:00 2001 From: onevcat Date: Tue, 14 Nov 2017 11:25:04 +0900 Subject: [PATCH] Add an option for only from memory cache or refresh --- Sources/ImageCache.swift | 4 ++ Sources/KingfisherOptionsInfo.swift | 11 ++++ .../KingfisherManagerTests.swift | 56 +++++++++++++++++++ .../KingfisherOptionsInfoTests.swift | 3 + 4 files changed, 74 insertions(+) diff --git a/Sources/ImageCache.swift b/Sources/ImageCache.swift index 82d1ae776..8d445b511 100755 --- a/Sources/ImageCache.swift +++ b/Sources/ImageCache.swift @@ -295,6 +295,10 @@ open class ImageCache { options.callbackDispatchQueue.safeAsync { completionHandler(image, .memory) } + } else if options.fromMemoryCacheOrRefresh { // Only allows to get images from memory cache. + options.callbackDispatchQueue.safeAsync { + completionHandler(nil, .none) + } } else { var sSelf: ImageCache! = self block = DispatchWorkItem(block: { diff --git a/Sources/KingfisherOptionsInfo.swift b/Sources/KingfisherOptionsInfo.swift index 73acd529a..1d275dc40 100755 --- a/Sources/KingfisherOptionsInfo.swift +++ b/Sources/KingfisherOptionsInfo.swift @@ -67,6 +67,11 @@ public enum KingfisherOptionsInfoItem { /// If set, `Kingfisher` will ignore the cache and try to fire a download task for the resource. case forceRefresh + + /// If set, `Kingfisher` will try to retrieve the image from memory cache first. If the image is not in memory + /// cache, then it will ignore the disk cache but download the image again from network. This is useful when + /// you want to display a changeable image behind the same url, while avoiding download it again and again. + case fromMemoryCacheOrRefresh /// If set, setting the image to an image view will happen with transition even when retrieved from cache. /// See `Transition` option for more. @@ -148,6 +153,7 @@ func <== (lhs: KingfisherOptionsInfoItem, rhs: KingfisherOptionsInfoItem) -> Boo case (.transition(_), .transition(_)): return true case (.downloadPriority(_), .downloadPriority(_)): return true case (.forceRefresh, .forceRefresh): return true + case (.fromMemoryCacheOrRefresh, .fromMemoryCacheOrRefresh): return true case (.forceTransition, .forceTransition): return true case (.cacheMemoryOnly, .cacheMemoryOnly): return true case (.onlyFromCache, .onlyFromCache): return true @@ -232,6 +238,11 @@ public extension Collection where Iterator.Element == KingfisherOptionsInfoItem public var forceRefresh: Bool { return contains{ $0 <== .forceRefresh } } + + /// Whether an image should be got only from memory cache or download. + public var fromMemoryCacheOrRefresh: Bool { + return contains{ $0 <== .fromMemoryCacheOrRefresh } + } /// Whether the transition should always happen or not. public var forceTransition: Bool { diff --git a/Tests/KingfisherTests/KingfisherManagerTests.swift b/Tests/KingfisherTests/KingfisherManagerTests.swift index 704c38665..d7c3020eb 100755 --- a/Tests/KingfisherTests/KingfisherManagerTests.swift +++ b/Tests/KingfisherTests/KingfisherManagerTests.swift @@ -454,6 +454,62 @@ class KingfisherManagerTests: XCTestCase { waitForExpectations(timeout: 5, handler: nil) } + + func testImageShouldOnlyFromMemoryCacheOrRefreshCanBeGotFromMemory() { + let expectation = self.expectation(description: "only from memory cache or refresh") + let URLString = testKeys[0] + _ = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData) + + let url = URL(string: URLString)! + + manager.retrieveImage(with: url, options: [.fromMemoryCacheOrRefresh], progressBlock: nil) { + image, _, type, _ in + // Can download and cache normally + XCTAssertNotNil(image) + XCTAssertEqual(type, .none) + + // Can still be got from memory even when disk cache cleared. + self.manager.cache.clearDiskCache { + self.manager.retrieveImage(with: url, options: [.fromMemoryCacheOrRefresh], progressBlock: nil) { + image, _, type, _ in + XCTAssertNotNil(image) + XCTAssertEqual(type, .memory) + + expectation.fulfill() + } + } + } + waitForExpectations(timeout: 5, handler: nil) + } + + func testImageShouldOnlyFromMemoryCacheOrRefreshCanRefreshIfNotInMemory() { + let expectation = self.expectation(description: "only from memory cache or refresh") + let URLString = testKeys[0] + _ = stubRequest("GET", URLString).andReturn(200)?.withBody(testImageData) + + let url = URL(string: URLString)! + + manager.retrieveImage(with: url, options: [.fromMemoryCacheOrRefresh], progressBlock: nil) { + image, _, type, _ in + // Can download and cache normally + XCTAssertNotNil(image) + XCTAssertEqual(type, .none) + XCTAssertEqual(self.manager.cache.imageCachedType(forKey: URLString), .memory) + + self.manager.cache.clearMemoryCache() + XCTAssertEqual(self.manager.cache.imageCachedType(forKey: URLString), .disk) + + self.manager.retrieveImage(with: url, options: [.fromMemoryCacheOrRefresh], progressBlock: nil) { + image, _, type, _ in + XCTAssertNotNil(image) + XCTAssertEqual(type, .none) + XCTAssertEqual(self.manager.cache.imageCachedType(forKey: URLString), .memory) + + expectation.fulfill() + } + } + waitForExpectations(timeout: 5, handler: nil) + } } class SimpleProcessor: ImageProcessor { diff --git a/Tests/KingfisherTests/KingfisherOptionsInfoTests.swift b/Tests/KingfisherTests/KingfisherOptionsInfoTests.swift index 8cea4672e..649b1dbcc 100755 --- a/Tests/KingfisherTests/KingfisherOptionsInfoTests.swift +++ b/Tests/KingfisherTests/KingfisherOptionsInfoTests.swift @@ -54,6 +54,7 @@ class KingfisherOptionsInfoTests: XCTestCase { XCTAssertEqual(options.downloadPriority, URLSessionTask.defaultPriority) XCTAssertFalse(options.forceRefresh) + XCTAssertFalse(options.fromMemoryCacheOrRefresh) XCTAssertFalse(options.cacheMemoryOnly) XCTAssertFalse(options.backgroundDecode) XCTAssertEqual(options.callbackDispatchQueue.label, DispatchQueue.main.label) @@ -84,6 +85,7 @@ class KingfisherOptionsInfoTests: XCTestCase { .transition(transition), .downloadPriority(0.8), .forceRefresh, + .fromMemoryCacheOrRefresh, .cacheMemoryOnly, .onlyFromCache, .backgroundDecode, @@ -108,6 +110,7 @@ class KingfisherOptionsInfoTests: XCTestCase { XCTAssertEqual(options.downloadPriority, 0.8) XCTAssertTrue(options.forceRefresh) + XCTAssertTrue(options.fromMemoryCacheOrRefresh) XCTAssertTrue(options.cacheMemoryOnly) XCTAssertTrue(options.onlyFromCache) XCTAssertTrue(options.backgroundDecode)