Просмотр исходного кода

Add an option for only from memory cache or refresh

onevcat 8 лет назад
Родитель
Сommit
7d40fae695

+ 4 - 0
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: {

+ 11 - 0
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 {

+ 56 - 0
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 {

+ 3 - 0
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)