Skip to content

Commit

Permalink
Merge pull request onevcat#878 from onevcat/fix/custom-indicator-asso…
Browse files Browse the repository at this point in the history
…ciate

Wrap indicator with Box for associated object
  • Loading branch information
onevcat authored Mar 17, 2018
2 parents 03b208e + ea7644a commit f080d3b
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 5 deletions.
14 changes: 12 additions & 2 deletions Demo/Demo/Kingfisher-Demo/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,22 @@ extension ViewController {
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as! CollectionViewCell

cell.cellImageView.kf.indicatorType = .activity

cell.cellImageView.kf.indicatorType = .custom(indicator: MyIndicator())
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 {
func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
let urls = indexPaths.flatMap {
Expand Down
10 changes: 10 additions & 0 deletions Kingfisher.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@
D12E0C871C47F7AF00AC98AD /* KingfisherOptionsInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12E0C4B1C47F23500AC98AD /* KingfisherOptionsInfoTests.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 */; };
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 */; };
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 */; };
Expand Down Expand Up @@ -493,6 +497,7 @@
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>"; };
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; };
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>"; };
Expand Down Expand Up @@ -849,6 +854,7 @@
children = (
D10945F41C526B6C001408EB /* String+MD5.swift */,
D10945F51C526B6C001408EB /* ThreadHelper.swift */,
D13EA67C205C189C004F625F /* Box.swift */,
);
name = Helpers;
sourceTree = "<group>";
Expand Down Expand Up @@ -1777,6 +1783,7 @@
D109461C1C526C61001408EB /* ImageDownloader.swift in Sources */,
D109461D1C526C61001408EB /* ImageTransition.swift in Sources */,
F78F5EBF1FCDDE42001A9111 /* ImageModifier.swift in Sources */,
D13EA67F205C189C004F625F /* Box.swift in Sources */,
4B2B8E4C1D70141000FC4749 /* ImageProcessor.swift in Sources */,
4BFBEE7F1D7D0C3600699FD3 /* RequestModifier.swift in Sources */,
4B7742411D87E08A0077024E /* Indicator.swift in Sources */,
Expand Down Expand Up @@ -1851,6 +1858,7 @@
D10946121C526C0D001408EB /* ImageView+Kingfisher.swift in Sources */,
D10946131C526C0D001408EB /* KingfisherManager.swift in Sources */,
D10946141C526C0D001408EB /* KingfisherOptionsInfo.swift in Sources */,
D13EA67E205C189C004F625F /* Box.swift in Sources */,
D9638BA11C7DBA660046523D /* ImagePrefetcher.swift in Sources */,
D10946151C526C0D001408EB /* Resource.swift in Sources */,
D10946161C526C0D001408EB /* String+MD5.swift in Sources */,
Expand Down Expand Up @@ -1880,6 +1888,7 @@
D10946281C526CE8001408EB /* KingfisherManager.swift in Sources */,
4BD8E04F1D9237E200A091BE /* Kingfisher.swift in Sources */,
D10946291C526CE8001408EB /* KingfisherOptionsInfo.swift in Sources */,
D13EA680205C189C004F625F /* Box.swift in Sources */,
D109462A1C526CE8001408EB /* Resource.swift in Sources */,
D109462B1C526CE8001408EB /* String+MD5.swift in Sources */,
D109462C1C526CE8001408EB /* ThreadHelper.swift in Sources */,
Expand All @@ -1903,6 +1912,7 @@
D10945FB1C526B86001408EB /* ImageView+Kingfisher.swift in Sources */,
D10945FC1C526B86001408EB /* KingfisherManager.swift in Sources */,
D10945FD1C526B86001408EB /* KingfisherOptionsInfo.swift in Sources */,
D13EA67D205C189C004F625F /* Box.swift in Sources */,
D9638BA01C7DBA660046523D /* ImagePrefetcher.swift in Sources */,
D10945FE1C526B86001408EB /* Resource.swift in Sources */,
D10945FF1C526B86001408EB /* String+MD5.swift in Sources */,
Expand Down
34 changes: 34 additions & 0 deletions Sources/Box.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// Box.swift
// Kingfisher
//
// Created by Wei Wang on 2018/3/17.
// Copyright (c) 2018 Wei Wang <[email protected]>
//
// 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
}
}
9 changes: 7 additions & 2 deletions Sources/ImageView+Kingfisher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,10 @@ extension Kingfisher where Base: ImageView {
/// It will be `nil` if `indicatorType` is `.none`.
public fileprivate(set) var indicator: Indicator? {
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 {
Expand All @@ -219,7 +222,9 @@ extension Kingfisher where Base: ImageView {
}

// 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)
}
}

Expand Down
16 changes: 15 additions & 1 deletion Tests/KingfisherTests/ImageViewExtensionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,21 @@ class ImageViewExtensionTests: XCTestCase {
XCTAssertNotNil(imageView.kf.indicator, "The indicator should exist when indicatorType is different than .none")
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 = View()
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
XCTAssertNil(imageView.kf.indicator, "The indicator should be removed when indicatorType is .none")
}
Expand Down

0 comments on commit f080d3b

Please sign in to comment.