Browse Source

Wrap indicator with Box for associated object

onevcat 8 years ago
parent
commit
96799e9d64

+ 12 - 2
Demo/Demo/Kingfisher-Demo/ViewController.swift

@@ -82,12 +82,22 @@ extension ViewController {
     override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
     override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
         let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as! CollectionViewCell
         let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as! CollectionViewCell
     
     
-        cell.cellImageView.kf.indicatorType = .activity
-        
+        cell.cellImageView.kf.indicatorType = .custom(indicator: MyIndicator())
         return cell
         return cell
     }
     }
 }
 }
 
 
+struct MyIndicator: Indicator {
+    let view: UIView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
+    
+    func startAnimatingView() { print("start"); view.isHidden = false }
+    func stopAnimatingView() { view.isHidden = true }
+    
+    init() {
+        view.backgroundColor = UIColor.blue
+    }
+}
+
 extension ViewController: UICollectionViewDataSourcePrefetching {
 extension ViewController: UICollectionViewDataSourcePrefetching {
     func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
     func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
         let urls = indexPaths.flatMap {
         let urls = indexPaths.flatMap {

+ 10 - 0
Kingfisher.xcodeproj/project.pbxproj

@@ -261,6 +261,10 @@
 		D12E0C871C47F7AF00AC98AD /* KingfisherOptionsInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12E0C4B1C47F23500AC98AD /* KingfisherOptionsInfoTests.swift */; };
 		D12E0C871C47F7AF00AC98AD /* KingfisherOptionsInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12E0C4B1C47F23500AC98AD /* KingfisherOptionsInfoTests.swift */; };
 		D12E0C891C47F7B700AC98AD /* KingfisherTestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12E0C4C1C47F23500AC98AD /* KingfisherTestHelper.swift */; };
 		D12E0C891C47F7B700AC98AD /* KingfisherTestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12E0C4C1C47F23500AC98AD /* KingfisherTestHelper.swift */; };
 		D12E0C8A1C47F7C000AC98AD /* dancing-banana.gif in Resources */ = {isa = PBXBuildFile; fileRef = D12E0C441C47F23500AC98AD /* dancing-banana.gif */; };
 		D12E0C8A1C47F7C000AC98AD /* dancing-banana.gif in Resources */ = {isa = PBXBuildFile; fileRef = D12E0C441C47F23500AC98AD /* dancing-banana.gif */; };
+		D13EA67D205C189C004F625F /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = D13EA67C205C189C004F625F /* Box.swift */; };
+		D13EA67E205C189C004F625F /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = D13EA67C205C189C004F625F /* Box.swift */; };
+		D13EA67F205C189C004F625F /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = D13EA67C205C189C004F625F /* Box.swift */; };
+		D13EA680205C189C004F625F /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = D13EA67C205C189C004F625F /* Box.swift */; };
 		D14146391E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill-mac.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D141462B1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill-mac.jpg */; };
 		D14146391E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill-mac.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D141462B1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill-mac.jpg */; };
 		D141463A1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D141462C1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill.jpg */; };
 		D141463A1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D141462C1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill.jpg */; };
 		D141463B1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D141462C1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill.jpg */; };
 		D141463B1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D141462C1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill.jpg */; };
@@ -493,6 +497,7 @@
 		D12E0C4D1C47F23500AC98AD /* KingfisherTests-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "KingfisherTests-Bridging-Header.h"; sourceTree = "<group>"; };
 		D12E0C4D1C47F23500AC98AD /* KingfisherTests-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "KingfisherTests-Bridging-Header.h"; sourceTree = "<group>"; };
 		D12E0C4E1C47F23500AC98AD /* UIButtonExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIButtonExtensionTests.swift; sourceTree = "<group>"; };
 		D12E0C4E1C47F23500AC98AD /* UIButtonExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIButtonExtensionTests.swift; sourceTree = "<group>"; };
 		D12E0C5F1C47F24800AC98AD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		D12E0C5F1C47F24800AC98AD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		D13EA67C205C189C004F625F /* Box.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Box.swift; path = Sources/Box.swift; sourceTree = "<group>"; };
 		D13F49D61BEDA67C00CE335D /* Kingfisher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Kingfisher.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		D13F49D61BEDA67C00CE335D /* Kingfisher.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Kingfisher.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		D141462B1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill-mac.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "kingfisher-resize-240-60-aspectFill-mac.jpg"; sourceTree = "<group>"; };
 		D141462B1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill-mac.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "kingfisher-resize-240-60-aspectFill-mac.jpg"; sourceTree = "<group>"; };
 		D141462C1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "kingfisher-resize-240-60-aspectFill.jpg"; sourceTree = "<group>"; };
 		D141462C1E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "kingfisher-resize-240-60-aspectFill.jpg"; sourceTree = "<group>"; };
@@ -849,6 +854,7 @@
 			children = (
 			children = (
 				D10945F41C526B6C001408EB /* String+MD5.swift */,
 				D10945F41C526B6C001408EB /* String+MD5.swift */,
 				D10945F51C526B6C001408EB /* ThreadHelper.swift */,
 				D10945F51C526B6C001408EB /* ThreadHelper.swift */,
+				D13EA67C205C189C004F625F /* Box.swift */,
 			);
 			);
 			name = Helpers;
 			name = Helpers;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -1777,6 +1783,7 @@
 				D109461C1C526C61001408EB /* ImageDownloader.swift in Sources */,
 				D109461C1C526C61001408EB /* ImageDownloader.swift in Sources */,
 				D109461D1C526C61001408EB /* ImageTransition.swift in Sources */,
 				D109461D1C526C61001408EB /* ImageTransition.swift in Sources */,
 				F78F5EBF1FCDDE42001A9111 /* ImageModifier.swift in Sources */,
 				F78F5EBF1FCDDE42001A9111 /* ImageModifier.swift in Sources */,
+				D13EA67F205C189C004F625F /* Box.swift in Sources */,
 				4B2B8E4C1D70141000FC4749 /* ImageProcessor.swift in Sources */,
 				4B2B8E4C1D70141000FC4749 /* ImageProcessor.swift in Sources */,
 				4BFBEE7F1D7D0C3600699FD3 /* RequestModifier.swift in Sources */,
 				4BFBEE7F1D7D0C3600699FD3 /* RequestModifier.swift in Sources */,
 				4B7742411D87E08A0077024E /* Indicator.swift in Sources */,
 				4B7742411D87E08A0077024E /* Indicator.swift in Sources */,
@@ -1851,6 +1858,7 @@
 				D10946121C526C0D001408EB /* ImageView+Kingfisher.swift in Sources */,
 				D10946121C526C0D001408EB /* ImageView+Kingfisher.swift in Sources */,
 				D10946131C526C0D001408EB /* KingfisherManager.swift in Sources */,
 				D10946131C526C0D001408EB /* KingfisherManager.swift in Sources */,
 				D10946141C526C0D001408EB /* KingfisherOptionsInfo.swift in Sources */,
 				D10946141C526C0D001408EB /* KingfisherOptionsInfo.swift in Sources */,
+				D13EA67E205C189C004F625F /* Box.swift in Sources */,
 				D9638BA11C7DBA660046523D /* ImagePrefetcher.swift in Sources */,
 				D9638BA11C7DBA660046523D /* ImagePrefetcher.swift in Sources */,
 				D10946151C526C0D001408EB /* Resource.swift in Sources */,
 				D10946151C526C0D001408EB /* Resource.swift in Sources */,
 				D10946161C526C0D001408EB /* String+MD5.swift in Sources */,
 				D10946161C526C0D001408EB /* String+MD5.swift in Sources */,
@@ -1880,6 +1888,7 @@
 				D10946281C526CE8001408EB /* KingfisherManager.swift in Sources */,
 				D10946281C526CE8001408EB /* KingfisherManager.swift in Sources */,
 				4BD8E04F1D9237E200A091BE /* Kingfisher.swift in Sources */,
 				4BD8E04F1D9237E200A091BE /* Kingfisher.swift in Sources */,
 				D10946291C526CE8001408EB /* KingfisherOptionsInfo.swift in Sources */,
 				D10946291C526CE8001408EB /* KingfisherOptionsInfo.swift in Sources */,
+				D13EA680205C189C004F625F /* Box.swift in Sources */,
 				D109462A1C526CE8001408EB /* Resource.swift in Sources */,
 				D109462A1C526CE8001408EB /* Resource.swift in Sources */,
 				D109462B1C526CE8001408EB /* String+MD5.swift in Sources */,
 				D109462B1C526CE8001408EB /* String+MD5.swift in Sources */,
 				D109462C1C526CE8001408EB /* ThreadHelper.swift in Sources */,
 				D109462C1C526CE8001408EB /* ThreadHelper.swift in Sources */,
@@ -1903,6 +1912,7 @@
 				D10945FB1C526B86001408EB /* ImageView+Kingfisher.swift in Sources */,
 				D10945FB1C526B86001408EB /* ImageView+Kingfisher.swift in Sources */,
 				D10945FC1C526B86001408EB /* KingfisherManager.swift in Sources */,
 				D10945FC1C526B86001408EB /* KingfisherManager.swift in Sources */,
 				D10945FD1C526B86001408EB /* KingfisherOptionsInfo.swift in Sources */,
 				D10945FD1C526B86001408EB /* KingfisherOptionsInfo.swift in Sources */,
+				D13EA67D205C189C004F625F /* Box.swift in Sources */,
 				D9638BA01C7DBA660046523D /* ImagePrefetcher.swift in Sources */,
 				D9638BA01C7DBA660046523D /* ImagePrefetcher.swift in Sources */,
 				D10945FE1C526B86001408EB /* Resource.swift in Sources */,
 				D10945FE1C526B86001408EB /* Resource.swift in Sources */,
 				D10945FF1C526B86001408EB /* String+MD5.swift in Sources */,
 				D10945FF1C526B86001408EB /* String+MD5.swift in Sources */,

+ 34 - 0
Sources/Box.swift

@@ -0,0 +1,34 @@
+//
+//  Box.swift
+//  Kingfisher
+//
+//  Created by Wei Wang on 2018/3/17.
+//  Copyright (c) 2018 Wei Wang <onevcat@gmail.com>
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+//
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+//
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+
+import Foundation
+
+class Box<T> {
+    let value: T
+    
+    init(_ value: T) {
+        self.value = value
+    }
+}

+ 7 - 2
Sources/ImageView+Kingfisher.swift

@@ -198,7 +198,10 @@ extension Kingfisher where Base: ImageView {
     /// It will be `nil` if `indicatorType` is `.none`.
     /// It will be `nil` if `indicatorType` is `.none`.
     public fileprivate(set) var indicator: Indicator? {
     public fileprivate(set) var indicator: Indicator? {
         get {
         get {
-            return objc_getAssociatedObject(base, &indicatorKey) as? Indicator
+            guard let box = objc_getAssociatedObject(base, &indicatorKey) as? Box<Indicator> else {
+                return nil
+            }
+            return box.value
         }
         }
         
         
         set {
         set {
@@ -219,7 +222,9 @@ extension Kingfisher where Base: ImageView {
             }
             }
             
             
             // Save in associated object
             // Save in associated object
-            objc_setAssociatedObject(base, &indicatorKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
+            // Wrap newValue with Box to workaround an issue that Swift does not recognize
+            // and casting protocol for associate object correctly. https://github.com/onevcat/Kingfisher/issues/872
+            objc_setAssociatedObject(base, &indicatorKey, newValue.map(Box.init), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
         }
         }
     }
     }
     
     

+ 15 - 1
Tests/KingfisherTests/ImageViewExtensionTests.swift

@@ -361,7 +361,21 @@ class ImageViewExtensionTests: XCTestCase {
         XCTAssertNotNil(imageView.kf.indicator, "The indicator should exist when indicatorType is different than .none")
         XCTAssertNotNil(imageView.kf.indicator, "The indicator should exist when indicatorType is different than .none")
         XCTAssertTrue(imageView.kf.indicator is ActivityIndicator)
         XCTAssertTrue(imageView.kf.indicator is ActivityIndicator)
 
 
-
+        imageView.kf.indicatorType = .none
+        XCTAssertNil(imageView.kf.indicator, "The indicator should be removed when indicatorType is .none")
+    }
+    
+    func testCustomizeStructIndicatorExisting() {
+        struct StructIndicator: Indicator {
+            let view = UIView()
+            func startAnimatingView() {}
+            func stopAnimatingView() {}
+        }
+        
+        imageView.kf.indicatorType = .custom(indicator: StructIndicator())
+        XCTAssertNotNil(imageView.kf.indicator, "The indicator should exist when indicatorType is different than .none")
+        XCTAssertTrue(imageView.kf.indicator is StructIndicator)
+        
         imageView.kf.indicatorType = .none
         imageView.kf.indicatorType = .none
         XCTAssertNil(imageView.kf.indicator, "The indicator should be removed when indicatorType is .none")
         XCTAssertNil(imageView.kf.indicator, "The indicator should be removed when indicatorType is .none")
     }
     }