Parcourir la source

Add clean notification and tests

onevcat il y a 10 ans
Parent
commit
b12121a661

+ 26 - 0
Kingfisher/ImageCache.swift

@@ -26,6 +26,9 @@
 
 
 import Foundation
 import Foundation
 
 
+public let KingfisherDidCleanDiskCacheNotification = "com.onevcat.Kingfisher.KingfisherDidCleanDiskCacheNotification"
+public let KingfisherDiskCacheCleanedHashKey = "com.onevcat.Kingfisher.cleanedHash"
+
 private let defaultCacheName = "default"
 private let defaultCacheName = "default"
 private let cacheReverseDNS = "com.onevcat.Kingfisher.ImageCache."
 private let cacheReverseDNS = "com.onevcat.Kingfisher.ImageCache."
 private let ioQueueName = "com.onevcat.Kingfisher.ImageCache.ioQueue."
 private let ioQueueName = "com.onevcat.Kingfisher.ImageCache.ioQueue."
@@ -415,6 +418,9 @@ extension ImageCache {
                     
                     
                     for fileURL in sortedFiles {
                     for fileURL in sortedFiles {
                         if (self.fileManager.removeItemAtURL(fileURL, error: nil)) {
                         if (self.fileManager.removeItemAtURL(fileURL, error: nil)) {
+                            
+                            URLsToDelete.append(fileURL)
+                            
                             if let fileSize = cachedFiles[fileURL]?[NSURLTotalFileAllocatedSizeKey] as? NSNumber {
                             if let fileSize = cachedFiles[fileURL]?[NSURLTotalFileAllocatedSizeKey] as? NSNumber {
                                 diskCacheSize -= fileSize.unsignedLongValue
                                 diskCacheSize -= fileSize.unsignedLongValue
                             }
                             }
@@ -427,6 +433,15 @@ extension ImageCache {
                 }
                 }
                 
                 
                 dispatch_async(dispatch_get_main_queue(), { () -> Void in
                 dispatch_async(dispatch_get_main_queue(), { () -> Void in
+                    
+                    if URLsToDelete.count != 0 {
+                        let cleanedHashes = URLsToDelete.map({ (url) -> String in
+                            return url.lastPathComponent!
+                        })
+                        
+                        NSNotificationCenter.defaultCenter().postNotificationName(KingfisherDidCleanDiskCacheNotification, object: self, userInfo: [KingfisherDiskCacheCleanedHashKey: cleanedHashes])
+                    }
+                    
                     if let completionHandler = completionHandler {
                     if let completionHandler = completionHandler {
                         completionHandler()
                         completionHandler()
                     }
                     }
@@ -499,6 +514,17 @@ public extension ImageCache {
         return CacheCheckResult(cached: false, cacheType: nil)
         return CacheCheckResult(cached: false, cacheType: nil)
     }
     }
     
     
+    /**
+    Get the hash for the key. This could be used for matching files.
+    
+    :param: key The key which is used for caching.
+    
+    :returns: Corresponding hash.
+    */
+    public func hashForKey(key: String) -> String {
+        return cacheFileNameForKey(key)
+    }
+    
     /**
     /**
     Calculate the disk size taken by cache. 
     Calculate the disk size taken by cache. 
     It is the total allocated size of the cached files in bytes.
     It is the total allocated size of the cached files in bytes.

+ 27 - 2
KingfisherTests/ImageCacheTests.swift

@@ -34,6 +34,7 @@ private let cacheName = "com.onevcat.Kingfisher.ImageCache.test"
 class ImageCacheTests: XCTestCase {
 class ImageCacheTests: XCTestCase {
 
 
     var cache: ImageCache!
     var cache: ImageCache!
+    var observer: NSObjectProtocol!
     
     
     override func setUp() {
     override func setUp() {
         super.setUp()
         super.setUp()
@@ -46,6 +47,7 @@ class ImageCacheTests: XCTestCase {
         super.tearDown()
         super.tearDown()
         cache.clearDiskCache()
         cache.clearDiskCache()
         cache = nil
         cache = nil
+        observer = nil
     }
     }
     
     
     func testMaxCachePeriodInSecond() {
     func testMaxCachePeriodInSecond() {
@@ -164,12 +166,35 @@ class ImageCacheTests: XCTestCase {
                     self.cache.retrieveImageInDiskCacheForKey(testKeys[0])
                     self.cache.retrieveImageInDiskCacheForKey(testKeys[0])
                 }
                 }
             })
             })
-        
             expectation.fulfill()
             expectation.fulfill()
+        }
+        
+        self.waitForExpectationsWithTimeout(15, handler: nil)
+    }
+    
+    func testCleanDiskCacheNotification() {
+        let expectation = expectationWithDescription("wait for retriving image")
+        
+        cache.storeImage(testImage, forKey: testKeys[0], toDisk: true) { () -> () in
+
+            self.observer = NSNotificationCenter.defaultCenter().addObserverForName(KingfisherDidCleanDiskCacheNotification, object: self.cache, queue: NSOperationQueue.mainQueue(), usingBlock: { (noti) -> Void in
+
+                XCTAssert(noti.object === self.cache, "The object of notification should be the cache object.")
+                
+                let hashes = noti.userInfo?[KingfisherDiskCacheCleanedHashKey] as! [String]
+                
+                XCTAssertEqual(1, hashes.count, "There should be one and only one file cleaned")
+                XCTAssertEqual(hashes.first!, self.cache.hashForKey(testKeys[0]), "The cleaned file should be the stored one.")
+                
+                NSNotificationCenter.defaultCenter().removeObserver(self.observer)
+                expectation.fulfill()
+            })
             
             
+            self.cache.maxCachePeriodInSecond = 0
+            self.cache.cleanExpiredDiskCache()
         }
         }
         
         
-        self.waitForExpectationsWithTimeout(5, handler: nil)
+        waitForExpectationsWithTimeout(1, handler: nil)
     }
     }
 
 
     // MARK: - Helper
     // MARK: - Helper

+ 17 - 1
KingfisherTests/ImageDownloaderTests.swift

@@ -144,6 +144,22 @@ class ImageDownloaderTests: XCTestCase {
         waitForExpectationsWithTimeout(1, handler: nil)
         waitForExpectationsWithTimeout(1, handler: nil)
     }
     }
     
     
+    func testServerNotModifiedResponse() {
+        let expectation = expectationWithDescription("wait for server response 304")
+        
+        let URLString = testKeys[0]
+        stubRequest("GET", URLString).andReturn(304)
+        
+        downloader.downloadImageWithURL(NSURL(string: URLString)!, options: KingfisherManager.OptionsNone, progressBlock: { (receivedSize, totalSize) -> () in
+            
+        }) { (image, error, imageURL) -> () in
+            XCTAssertNotNil(error, "There should be an error since server returning 304 and no image downloaded.")
+            XCTAssertEqual(error!.code, KingfisherError.NotModified.rawValue, "The error should be NotModified.")
+            expectation.fulfill()
+        }
+        waitForExpectationsWithTimeout(1, handler: nil)
+    }
+    
     // Since we could not receive one challage, no test for trusted hosts currently.
     // Since we could not receive one challage, no test for trusted hosts currently.
     // See http://stackoverflow.com/questions/27065372/why-is-a-https-nsurlsession-connection-only-challenged-once-per-domain for more.
     // See http://stackoverflow.com/questions/27065372/why-is-a-https-nsurlsession-connection-only-challenged-once-per-domain for more.
     func testSSLCertificateValidation() {
     func testSSLCertificateValidation() {
@@ -155,7 +171,7 @@ class ImageDownloaderTests: XCTestCase {
         
         
         downloader.downloadImageWithURL(URL, progressBlock: nil, completionHandler: { (image, error, imageURL) -> () in
         downloader.downloadImageWithURL(URL, progressBlock: nil, completionHandler: { (image, error, imageURL) -> () in
             XCTAssertNotNil(error, "Error should not be nil")
             XCTAssertNotNil(error, "Error should not be nil")
-            XCTAssert(error?.code == NSURLErrorServerCertificateUntrusted, "Error should be NSURLErrorServerCertificateUntrusted")
+            XCTAssert(error?.code == NSURLErrorServerCertificateUntrusted, "Error should be NSURLErrorServerCertificateUntrusted, but \(error)")
             expectation.fulfill()
             expectation.fulfill()
             LSNocilla.sharedInstance().start()
             LSNocilla.sharedInstance().start()
         })
         })