From d85613800a58ad4b13e6bc1401026b7f0a80006d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20D=2E=20Moreira?= Date: Tue, 6 Sep 2016 12:39:10 +0200 Subject: [PATCH 1/6] Wrapped associated objects --- Kingfisher.xcodeproj/project.pbxproj | 10 ++++++ Sources/Image.swift | 16 ++++----- Sources/ImageView+Kingfisher.swift | 16 ++++----- Sources/NSButton+Kingfisher.swift | 18 +++++------ Sources/UIButton+Kingfisher.swift | 16 ++++----- Sources/WrappedAssociatedObjects.swift | 45 ++++++++++++++++++++++++++ 6 files changed, 88 insertions(+), 33 deletions(-) create mode 100644 Sources/WrappedAssociatedObjects.swift diff --git a/Kingfisher.xcodeproj/project.pbxproj b/Kingfisher.xcodeproj/project.pbxproj index 808fec2c9..793eaa650 100644 --- a/Kingfisher.xcodeproj/project.pbxproj +++ b/Kingfisher.xcodeproj/project.pbxproj @@ -19,6 +19,10 @@ 4B98674F1CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B98674E1CD1CF42003ADAC7 /* AnimatedImageView.swift */; }; 4B9867501CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B98674E1CD1CF42003ADAC7 /* AnimatedImageView.swift */; }; B43007AC86DBFFFD1AC6EDD1 /* libPods-KingfisherTests-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 798E024A9311DC80470CF240 /* libPods-KingfisherTests-tvOS.a */; }; + CD4593971D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */; }; + CD4593981D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */; }; + CD4593991D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */; }; + CD45939A1D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */; }; D10945F71C526B86001408EB /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = D10945EA1C526B6C001408EB /* Image.swift */; }; D10945F81C526B86001408EB /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D10945EB1C526B6C001408EB /* ImageCache.swift */; }; D10945F91C526B86001408EB /* ImageDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D10945EC1C526B6C001408EB /* ImageDownloader.swift */; }; @@ -267,6 +271,7 @@ A8D69912DD16C2942EB1F40E /* Pods-KingfisherTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KingfisherTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-KingfisherTests/Pods-KingfisherTests.release.xcconfig"; sourceTree = ""; }; A9E621E297FEFAD35D39C34E /* libPods-KingfisherTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-KingfisherTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; B6B5C590A36C8E84C5B16C3E /* Pods-KingfisherTests-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KingfisherTests-tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-KingfisherTests-tvOS/Pods-KingfisherTests-tvOS.debug.xcconfig"; sourceTree = ""; }; + CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WrappedAssociatedObjects.swift; path = Sources/WrappedAssociatedObjects.swift; sourceTree = ""; }; D10945EA1C526B6C001408EB /* Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Image.swift; path = Sources/Image.swift; sourceTree = ""; }; D10945EB1C526B6C001408EB /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ImageCache.swift; path = Sources/ImageCache.swift; sourceTree = ""; }; D10945EC1C526B6C001408EB /* ImageDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ImageDownloader.swift; path = Sources/ImageDownloader.swift; sourceTree = ""; }; @@ -459,6 +464,7 @@ D10945F51C526B6C001408EB /* ThreadHelper.swift */, D10945F61C526B6C001408EB /* UIButton+Kingfisher.swift */, 182FFF771CC9ACBA004B728D /* NSButton+Kingfisher.swift */, + CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */, ); name = Sources; sourceTree = ""; @@ -1232,6 +1238,7 @@ D109461E1C526C61001408EB /* ImageView+Kingfisher.swift in Sources */, D109461F1C526C61001408EB /* KingfisherManager.swift in Sources */, 182FFF781CC9ACBA004B728D /* NSButton+Kingfisher.swift in Sources */, + CD4593991D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */, D10946201C526C61001408EB /* KingfisherOptionsInfo.swift in Sources */, D10946211C526C61001408EB /* Resource.swift in Sources */, D9638BA21C7DBA660046523D /* ImagePrefetcher.swift in Sources */, @@ -1297,6 +1304,7 @@ files = ( D109460E1C526C0D001408EB /* Image.swift in Sources */, 4B9867501CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */, + CD4593981D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */, D109460F1C526C0D001408EB /* ImageCache.swift in Sources */, D10946101C526C0D001408EB /* ImageDownloader.swift in Sources */, D10946111C526C0D001408EB /* ImageTransition.swift in Sources */, @@ -1317,6 +1325,7 @@ files = ( D109462D1C526CF5001408EB /* ImageTransition.swift in Sources */, D10946251C526CE8001408EB /* Image.swift in Sources */, + CD45939A1D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */, D10946261C526CE8001408EB /* ImageCache.swift in Sources */, D9638BA31C7DBA660046523D /* ImagePrefetcher.swift in Sources */, D10946271C526CE8001408EB /* ImageDownloader.swift in Sources */, @@ -1353,6 +1362,7 @@ files = ( D10945F71C526B86001408EB /* Image.swift in Sources */, 4B98674F1CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */, + CD4593971D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */, D10945F81C526B86001408EB /* ImageCache.swift in Sources */, D10945F91C526B86001408EB /* ImageDownloader.swift in Sources */, D10945FA1C526B86001408EB /* ImageTransition.swift in Sources */, diff --git a/Sources/Image.swift b/Sources/Image.swift index 470f12ff2..6ea6cce2b 100644 --- a/Sources/Image.swift +++ b/Sources/Image.swift @@ -56,19 +56,19 @@ extension Image { private(set) var kf_images: [Image]? { get { - return objc_getAssociatedObject(self, &imagesKey) as? [Image] + return getAssociatedObject(self, associativeKey: &imagesKey) } set { - objc_setAssociatedObject(self, &imagesKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: newValue, associativeKey: &imagesKey) } } private(set) var kf_duration: NSTimeInterval { get { - return objc_getAssociatedObject(self, &durationKey) as? NSTimeInterval ?? 0.0 + return getAssociatedObject(self, associativeKey: &durationKey) ?? 0.0 } set { - objc_setAssociatedObject(self, &durationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: newValue, associativeKey: &durationKey) } } @@ -87,19 +87,19 @@ extension Image { private(set) var kf_imageSource: ImageSource? { get { - return objc_getAssociatedObject(self, &imageSourceKey) as? ImageSource + return getAssociatedObject(self, associativeKey: &imageSourceKey) } set { - objc_setAssociatedObject(self, &imageSourceKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: newValue, associativeKey: &imageSourceKey) } } private(set) var kf_animatedImageData: NSData? { get { - return objc_getAssociatedObject(self, &animatedImageDataKey) as? NSData + return getAssociatedObject(self, associativeKey: &animatedImageDataKey) } set { - objc_setAssociatedObject(self, &animatedImageDataKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: newValue, associativeKey: &animatedImageDataKey) } } #endif diff --git a/Sources/ImageView+Kingfisher.swift b/Sources/ImageView+Kingfisher.swift index 4b4bd824e..4d09f1ea1 100644 --- a/Sources/ImageView+Kingfisher.swift +++ b/Sources/ImageView+Kingfisher.swift @@ -193,18 +193,18 @@ private var imageTaskKey: Void? extension ImageView { /// Get the image URL binded to this image view. public var kf_webURL: NSURL? { - return objc_getAssociatedObject(self, &lastURLKey) as? NSURL + return getAssociatedObject(self, associativeKey: &lastURLKey) } private func kf_setWebURL(URL: NSURL) { - objc_setAssociatedObject(self, &lastURLKey, URL, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: URL, associativeKey: &lastURLKey) } /// Whether show an animating indicator when the image view is loading an image or not. /// Default is false. public var kf_showIndicatorWhenLoading: Bool { get { - if let result = objc_getAssociatedObject(self, &showIndicatorWhenLoadingKey) as? NSNumber { + if let result:NSNumber = getAssociatedObject(self, associativeKey: &showIndicatorWhenLoadingKey) { return result.boolValue } else { return false @@ -247,7 +247,7 @@ extension ImageView { kf_setIndicator(nil) } - objc_setAssociatedObject(self, &showIndicatorWhenLoadingKey, NSNumber(bool: newValue), .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value:NSNumber(bool: newValue), associativeKey: &showIndicatorWhenLoadingKey) } } } @@ -255,19 +255,19 @@ extension ImageView { /// The indicator view showing when loading. This will be `nil` if `kf_showIndicatorWhenLoading` is false. /// You may want to use this to set the indicator style or color when you set `kf_showIndicatorWhenLoading` to true. public var kf_indicator: IndicatorView? { - return objc_getAssociatedObject(self, &indicatorKey) as? IndicatorView + return getAssociatedObject(self, associativeKey: &indicatorKey) } private func kf_setIndicator(indicator: IndicatorView?) { - objc_setAssociatedObject(self, &indicatorKey, indicator, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: indicator, associativeKey: &indicatorKey) } private var kf_imageTask: RetrieveImageTask? { - return objc_getAssociatedObject(self, &imageTaskKey) as? RetrieveImageTask + return getAssociatedObject(self, associativeKey: &imageTaskKey) } private func kf_setImageTask(task: RetrieveImageTask?) { - objc_setAssociatedObject(self, &imageTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: task, associativeKey: &imageTaskKey) } } diff --git a/Sources/NSButton+Kingfisher.swift b/Sources/NSButton+Kingfisher.swift index 3e686da41..57c9fbb27 100644 --- a/Sources/NSButton+Kingfisher.swift +++ b/Sources/NSButton+Kingfisher.swift @@ -127,19 +127,19 @@ private var imageTaskKey: Void? extension NSButton { /// Get the image URL binded to this image view. public var kf_webURL: NSURL? { - return objc_getAssociatedObject(self, &lastURLKey) as? NSURL + return getAssociatedObject(self, associativeKey: &lastURLKey) } private func kf_setWebURL(URL: NSURL) { - objc_setAssociatedObject(self, &lastURLKey, URL, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: URL, associativeKey: &lastURLKey) } private var kf_imageTask: RetrieveImageTask? { - return objc_getAssociatedObject(self, &imageTaskKey) as? RetrieveImageTask + return getAssociatedObject(self, associativeKey: &imageTaskKey) } - + private func kf_setImageTask(task: RetrieveImageTask?) { - objc_setAssociatedObject(self, &imageTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: task, associativeKey: &imageTaskKey) } } @@ -245,19 +245,19 @@ extension NSButton { */ public var kf_alternateWebURL: NSURL? { - return objc_getAssociatedObject(self, &lastAlternateURLKey) as? NSURL + return getAssociatedObject(self, associativeKey: &lastAlternateURLKey) } private func kf_setAlternateWebURL(URL: NSURL) { - objc_setAssociatedObject(self, &lastAlternateURLKey, URL, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: URL, associativeKey: &lastAlternateURLKey) } private var kf_alternateImageTask: RetrieveImageTask? { - return objc_getAssociatedObject(self, &alternateImageTaskKey) as? RetrieveImageTask + return getAssociatedObject(self, associativeKey: &alternateImageTaskKey) } private func kf_setAlternateImageTask(task: RetrieveImageTask?) { - objc_setAssociatedObject(self, &alternateImageTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: task, associativeKey: &alternateImageTaskKey) } } diff --git a/Sources/UIButton+Kingfisher.swift b/Sources/UIButton+Kingfisher.swift index 4453af650..d37ac1b14 100644 --- a/Sources/UIButton+Kingfisher.swift +++ b/Sources/UIButton+Kingfisher.swift @@ -140,7 +140,7 @@ extension UIButton { } private var kf_webURLs: NSMutableDictionary { - var dictionary = objc_getAssociatedObject(self, &lastURLKey) as? NSMutableDictionary + var dictionary:NSMutableDictionary? = getAssociatedObject(self, associativeKey: &lastURLKey) if dictionary == nil { dictionary = NSMutableDictionary() kf_setWebURLs(dictionary!) @@ -149,15 +149,15 @@ extension UIButton { } private func kf_setWebURLs(URLs: NSMutableDictionary) { - objc_setAssociatedObject(self, &lastURLKey, URLs, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: URLs, associativeKey: &lastURLKey) } private var kf_imageTask: RetrieveImageTask? { - return objc_getAssociatedObject(self, &imageTaskKey) as? RetrieveImageTask + return getAssociatedObject(self, associativeKey: &imageTaskKey) } private func kf_setImageTask(task: RetrieveImageTask?) { - objc_setAssociatedObject(self, &imageTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: task, associativeKey: &imageTaskKey) } } @@ -276,7 +276,7 @@ extension UIButton { } private var kf_backgroundWebURLs: NSMutableDictionary { - var dictionary = objc_getAssociatedObject(self, &lastBackgroundURLKey) as? NSMutableDictionary + var dictionary:NSMutableDictionary? = getAssociatedObject(self, associativeKey: &lastBackgroundURLKey) if dictionary == nil { dictionary = NSMutableDictionary() kf_setBackgroundWebURLs(dictionary!) @@ -285,15 +285,15 @@ extension UIButton { } private func kf_setBackgroundWebURLs(URLs: NSMutableDictionary) { - objc_setAssociatedObject(self, &lastBackgroundURLKey, URLs, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: URLs, associativeKey: &lastBackgroundURLKey) } private var kf_backgroundImageTask: RetrieveImageTask? { - return objc_getAssociatedObject(self, &backgroundImageTaskKey) as? RetrieveImageTask + return getAssociatedObject(self, associativeKey: &backgroundImageTaskKey) } private func kf_setBackgroundImageTask(task: RetrieveImageTask?) { - objc_setAssociatedObject(self, &backgroundImageTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + setAssociatedObject(self, value: task, associativeKey: &backgroundImageTaskKey) } } diff --git a/Sources/WrappedAssociatedObjects.swift b/Sources/WrappedAssociatedObjects.swift new file mode 100644 index 000000000..d076b7ba3 --- /dev/null +++ b/Sources/WrappedAssociatedObjects.swift @@ -0,0 +1,45 @@ +// +// AssociatedObjects.swift +// Kingfisher +// +// Created by João D. Moreira on 31/08/16. +// Copyright © 2016 Wei Wang. All rights reserved. +// + +import ObjectiveC + +/** + * This file provides a wrapper around Objective-C runtime associated objects. + * All values are wrapped in an instance of Wrapper allowing us to persist Swift value types. + */ +private final class Wrapper { + let value: T + init(_ x: T) { + value = x + } +} + +private func wrap(x: T) -> Wrapper { + return Wrapper(x) +} + +func setAssociatedObject(object: AnyObject, value: T, associativeKey: UnsafePointer, policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN_NONATOMIC) { + if let v: AnyObject = value as? AnyObject { + objc_setAssociatedObject(object, associativeKey, v, policy) + } else { + objc_setAssociatedObject(object, associativeKey, wrap(value), policy) + } +} + +func getAssociatedObject(object: AnyObject, associativeKey: UnsafePointer) -> T? { + + let v = objc_getAssociatedObject(object, associativeKey) + + if let v = v as? T { + return v + } else if let v = v as? Wrapper { + return v.value + } else { + return nil + } +} From a19603394b0c7bd4addf46d70f14a3b9ddd2db93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20D=2E=20Moreira?= Date: Wed, 7 Sep 2016 12:01:43 +0200 Subject: [PATCH 2/6] kf_indicator is now a protocol. Also added kf_indicatorType and two structs that conform to the Indicator protocol --- Kingfisher.xcodeproj/project.pbxproj | 8 ++ Sources/ImageView+Kingfisher.swift | 174 ++++++++++---------------- Sources/Indicator.swift | 176 +++++++++++++++++++++++++++ 3 files changed, 249 insertions(+), 109 deletions(-) create mode 100644 Sources/Indicator.swift diff --git a/Kingfisher.xcodeproj/project.pbxproj b/Kingfisher.xcodeproj/project.pbxproj index 793eaa650..c78078245 100644 --- a/Kingfisher.xcodeproj/project.pbxproj +++ b/Kingfisher.xcodeproj/project.pbxproj @@ -19,6 +19,9 @@ 4B98674F1CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B98674E1CD1CF42003ADAC7 /* AnimatedImageView.swift */; }; 4B9867501CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B98674E1CD1CF42003ADAC7 /* AnimatedImageView.swift */; }; B43007AC86DBFFFD1AC6EDD1 /* libPods-KingfisherTests-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 798E024A9311DC80470CF240 /* libPods-KingfisherTests-tvOS.a */; }; + CD2C73541D7F040B00A1D819 /* Indicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD2C73531D7F040B00A1D819 /* Indicator.swift */; }; + CD2C73551D7F040B00A1D819 /* Indicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD2C73531D7F040B00A1D819 /* Indicator.swift */; }; + CD2C73561D7F040B00A1D819 /* Indicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD2C73531D7F040B00A1D819 /* Indicator.swift */; }; CD4593971D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */; }; CD4593981D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */; }; CD4593991D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */; }; @@ -271,6 +274,7 @@ A8D69912DD16C2942EB1F40E /* Pods-KingfisherTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KingfisherTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-KingfisherTests/Pods-KingfisherTests.release.xcconfig"; sourceTree = ""; }; A9E621E297FEFAD35D39C34E /* libPods-KingfisherTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-KingfisherTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; B6B5C590A36C8E84C5B16C3E /* Pods-KingfisherTests-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KingfisherTests-tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-KingfisherTests-tvOS/Pods-KingfisherTests-tvOS.debug.xcconfig"; sourceTree = ""; }; + CD2C73531D7F040B00A1D819 /* Indicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Indicator.swift; path = Sources/Indicator.swift; sourceTree = ""; }; CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WrappedAssociatedObjects.swift; path = Sources/WrappedAssociatedObjects.swift; sourceTree = ""; }; D10945EA1C526B6C001408EB /* Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Image.swift; path = Sources/Image.swift; sourceTree = ""; }; D10945EB1C526B6C001408EB /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ImageCache.swift; path = Sources/ImageCache.swift; sourceTree = ""; }; @@ -465,6 +469,7 @@ D10945F61C526B6C001408EB /* UIButton+Kingfisher.swift */, 182FFF771CC9ACBA004B728D /* NSButton+Kingfisher.swift */, CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */, + CD2C73531D7F040B00A1D819 /* Indicator.swift */, ); name = Sources; sourceTree = ""; @@ -1232,6 +1237,7 @@ buildActionMask = 2147483647; files = ( D109461A1C526C61001408EB /* Image.swift in Sources */, + CD2C73561D7F040B00A1D819 /* Indicator.swift in Sources */, D109461B1C526C61001408EB /* ImageCache.swift in Sources */, D109461C1C526C61001408EB /* ImageDownloader.swift in Sources */, D109461D1C526C61001408EB /* ImageTransition.swift in Sources */, @@ -1315,6 +1321,7 @@ D10946151C526C0D001408EB /* Resource.swift in Sources */, D10946161C526C0D001408EB /* String+MD5.swift in Sources */, D10946171C526C0D001408EB /* ThreadHelper.swift in Sources */, + CD2C73551D7F040B00A1D819 /* Indicator.swift in Sources */, D10946181C526C0D001408EB /* UIButton+Kingfisher.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1373,6 +1380,7 @@ D10945FE1C526B86001408EB /* Resource.swift in Sources */, D10945FF1C526B86001408EB /* String+MD5.swift in Sources */, D10946001C526B86001408EB /* ThreadHelper.swift in Sources */, + CD2C73541D7F040B00A1D819 /* Indicator.swift in Sources */, D10946011C526B86001408EB /* UIButton+Kingfisher.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Sources/ImageView+Kingfisher.swift b/Sources/ImageView+Kingfisher.swift index 4d09f1ea1..ddacd7b79 100644 --- a/Sources/ImageView+Kingfisher.swift +++ b/Sources/ImageView+Kingfisher.swift @@ -28,11 +28,9 @@ #if os(OSX) import AppKit typealias ImageView = NSImageView -public typealias IndicatorView = NSProgressIndicator #else import UIKit typealias ImageView = UIImageView -public typealias IndicatorView = UIActivityIndicatorView #endif // MARK: - Set Images @@ -98,13 +96,8 @@ extension ImageView { return RetrieveImageTask.emptyTask } - let showIndicatorWhenLoading = kf_showIndicatorWhenLoading - var indicator: IndicatorView? = nil - if showIndicatorWhenLoading { - indicator = kf_indicator - indicator?.hidden = false - indicator?.kf_startAnimating() - } + let maybeIndicator = kf_indicator + maybeIndicator?.startAnimatingView() kf_setWebURL(resource.downloadURL) @@ -129,7 +122,7 @@ extension ImageView { sSelf.kf_setImageTask(nil) guard let image = image else { - indicator?.kf_stopAnimating() + maybeIndicator?.stopAnimatingView() completionHandler?(image: nil, error: error, cacheType: cacheType, imageURL: imageURL) return } @@ -139,7 +132,7 @@ extension ImageView { #if !os(OSX) UIView.transitionWithView(sSelf, duration: 0.0, options: [], animations: { - indicator?.kf_stopAnimating() + maybeIndicator?.stopAnimatingView() }, completion: { finished in UIView.transitionWithView(sSelf, duration: transition.duration, @@ -155,7 +148,7 @@ extension ImageView { }) #endif } else { - indicator?.kf_stopAnimating() + maybeIndicator?.stopAnimatingView() sSelf.image = image completionHandler?(image: image, error: error, cacheType: cacheType, imageURL: imageURL) } @@ -184,10 +177,22 @@ extension ImageView { } } +/** + Enum for the types of indicators that the user can choose from. + */ +extension ImageView { + public enum IndicatorType { + case none // no indicator + case custom(indicator: Indicator) // user custom indicator + case activity // activity indicator + case image(imageData: NSData) // supports gif + } +} + // MARK: - Associated Object private var lastURLKey: Void? private var indicatorKey: Void? -private var showIndicatorWhenLoadingKey: Void? +private var indicatorTypeKey: Void? private var imageTaskKey: Void? extension ImageView { @@ -199,69 +204,62 @@ extension ImageView { private func kf_setWebURL(URL: NSURL) { setAssociatedObject(self, value: URL, associativeKey: &lastURLKey) } - - /// Whether show an animating indicator when the image view is loading an image or not. - /// Default is false. - public var kf_showIndicatorWhenLoading: Bool { + + + /// Holds which indicator type is going to be used. + /// Default is .none + public var kf_indicatorType: IndicatorType { get { - if let result:NSNumber = getAssociatedObject(self, associativeKey: &showIndicatorWhenLoadingKey) { - return result.boolValue - } else { - return false - } + let indicator: IndicatorType? = getAssociatedObject(self, associativeKey: &indicatorTypeKey) + return indicator ?? .none } set { - if kf_showIndicatorWhenLoading == newValue { - return - } else { - if newValue { - -#if os(OSX) - let indicator = NSProgressIndicator(frame: CGRect(x: 0, y: 0, width: 16, height: 16)) - - #if swift(>=2.3) - indicator.controlSize = .Small - #else - indicator.controlSize = .SmallControlSize - #endif - indicator.style = .SpinningStyle -#else - #if os(tvOS) - let indicatorStyle = UIActivityIndicatorViewStyle.White - #else - let indicatorStyle = UIActivityIndicatorViewStyle.Gray - #endif - let indicator = UIActivityIndicatorView(activityIndicatorStyle:indicatorStyle) - indicator.autoresizingMask = [.FlexibleLeftMargin, .FlexibleRightMargin, .FlexibleBottomMargin, .FlexibleTopMargin] -#endif + switch newValue { + case .none: + kf_indicator = nil + case .activity: + kf_indicator = ActivityIndicator() + case .image(let data): + kf_indicator = ImageIndicator(imageData: data) + case .custom(let indicator): + kf_indicator = indicator + } - indicator.kf_center = CGPoint(x: CGRectGetMidX(bounds), y: CGRectGetMidY(bounds)) - indicator.hidden = true + setAssociatedObject(self, value: newValue, associativeKey: &indicatorTypeKey) + } + } - self.addSubview(indicator) - - kf_setIndicator(indicator) - } else { - kf_indicator?.removeFromSuperview() - kf_setIndicator(nil) - } - - setAssociatedObject(self, value:NSNumber(bool: newValue), associativeKey: &showIndicatorWhenLoadingKey) + /// `kf_indicator` holds any type that conforms to the protocol `Indicator`. + /// The protocol `Indicator` has a `view` property that will be shown when loading an image. + /// Everything will be `nil` if `kf_indicatorType` is .none. + public private(set) var kf_indicator: Indicator? { + get { + let indicator: (Indicator?)? = getAssociatedObject(self, associativeKey: &indicatorKey) + return indicator ?? nil + } + + set { + // Remove previous + if let previousIndicator = kf_indicator { + previousIndicator.view.removeFromSuperview() } + + // Add new + if var newIndicator = newValue { + newIndicator.view.frame = self.frame + newIndicator.viewCenter = CGPoint(x: bounds.midX, y: bounds.midY) + newIndicator.view.hidden = true + self.addSubview(newIndicator.view) + } + + // Save in associated object + setAssociatedObject(self, + value: newValue, + associativeKey: &indicatorKey) } } - - /// The indicator view showing when loading. This will be `nil` if `kf_showIndicatorWhenLoading` is false. - /// You may want to use this to set the indicator style or color when you set `kf_showIndicatorWhenLoading` to true. - public var kf_indicator: IndicatorView? { - return getAssociatedObject(self, associativeKey: &indicatorKey) - } - - private func kf_setIndicator(indicator: IndicatorView?) { - setAssociatedObject(self, value: indicator, associativeKey: &indicatorKey) - } - + private var kf_imageTask: RetrieveImageTask? { return getAssociatedObject(self, associativeKey: &imageTaskKey) } @@ -270,45 +268,3 @@ extension ImageView { setAssociatedObject(self, value: task, associativeKey: &imageTaskKey) } } - - -extension IndicatorView { - func kf_startAnimating() { - #if os(OSX) - startAnimation(nil) - #else - startAnimating() - #endif - hidden = false - } - - func kf_stopAnimating() { - #if os(OSX) - stopAnimation(nil) - #else - stopAnimating() - #endif - hidden = true - } - - #if os(OSX) - var kf_center: CGPoint { - get { - return CGPoint(x: frame.origin.x + frame.size.width / 2.0, y: frame.origin.y + frame.size.height / 2.0 ) - } - set { - let newFrame = CGRect(x: newValue.x - frame.size.width / 2.0, y: newValue.y - frame.size.height / 2.0, width: frame.size.width, height: frame.size.height) - frame = newFrame - } - } - #else - var kf_center: CGPoint { - get { - return center - } - set { - center = newValue - } - } - #endif -} diff --git a/Sources/Indicator.swift b/Sources/Indicator.swift new file mode 100644 index 000000000..2d05e9659 --- /dev/null +++ b/Sources/Indicator.swift @@ -0,0 +1,176 @@ +// +// Indicator.swift +// Kingfisher +// +// Created by João D. Moreira on 30/08/16. +// +// Copyright (c) 2016 Wei Wang +// +// 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. + +#if os(OSX) + import AppKit +#else + import UIKit +#endif + +#if os(OSX) + public typealias IndicatorView = NSView +#else + public typealias IndicatorView = UIView +#endif + +// MARK: - Indicator Protocol +public protocol Indicator { + func startAnimatingView() + func stopAnimatingView() + + var viewCenter: CGPoint { get set } + var view: IndicatorView { get } +} + +extension Indicator { + #if os(OSX) + var viewCenter: CGPoint { + get { + let frame = view.frame + return CGPoint(x: frame.origin.x + frame.size.width / 2.0, y: frame.origin.y + frame.size.height / 2.0 ) + } + set { + let frame = view.frame + let newFrame = CGRect(x: newValue.x - frame.size.width / 2.0, + y: newValue.y - frame.size.height / 2.0, + width: frame.size.width, + height: frame.size.height) + view.frame = newFrame + } + } + #else + var viewCenter: CGPoint { + get { + return view.center + } + set { + view.center = newValue + } + } + #endif +} + +// MARK: - ActivityIndicator +// Displays a NSProgressIndicator / UIActivityIndicatorView +struct ActivityIndicator: Indicator { + + #if os(OSX) + private let activityIndicatorView: NSProgressIndicator + #else + private let activityIndicatorView: UIActivityIndicatorView + #endif + + var view: IndicatorView { + return activityIndicatorView + } + + func startAnimatingView() { + #if os(OSX) + activityIndicatorView.startAnimation(nil) + #else + activityIndicatorView.startAnimating() + #endif + activityIndicatorView.hidden = false + } + + func stopAnimatingView() { + #if os(OSX) + activityIndicatorView.stopAnimation(nil) + #else + activityIndicatorView.stopAnimating() + #endif + activityIndicatorView.hidden = true + } + + init() { + #if os(OSX) + activityIndicatorView = NSProgressIndicator(frame: CGRect(x: 0, y: 0, width: 16, height: 16)) + + #if swift(>=2.3) + activityIndicatorView.controlSize = .Small + #else + activityIndicatorView.controlSize = .SmallControlSize + #endif + activityIndicatorView.style = .SpinningStyle + #else + #if os(tvOS) + let indicatorStyle = UIActivityIndicatorViewStyle.White + #else + let indicatorStyle = UIActivityIndicatorViewStyle.Gray + #endif + activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle:indicatorStyle) + activityIndicatorView.autoresizingMask = [.FlexibleLeftMargin, .FlexibleRightMargin, .FlexibleBottomMargin, .FlexibleTopMargin] + #endif + } +} + +// MARK: - ImageIndicator +// Displays an ImageView. Supports gif +struct ImageIndicator: Indicator { + private let animatedImageIndicatorView: ImageView + + var view: IndicatorView { + return animatedImageIndicatorView + } + + init(imageData data: NSData) { + + let image = Image.kf_imageWithData(data, scale: 1.0, preloadAllGIFData: true) + animatedImageIndicatorView = ImageView() + animatedImageIndicatorView.image = image + + #if os(OSX) + // Need for gif to animate on OSX + self.animatedImageIndicatorView.imageScaling = .ScaleNone + self.animatedImageIndicatorView.canDrawSubviewsIntoLayer = true + #else + animatedImageIndicatorView.contentMode = .Center + + animatedImageIndicatorView.autoresizingMask = [.FlexibleLeftMargin, + .FlexibleRightMargin, + .FlexibleBottomMargin, + .FlexibleTopMargin] + #endif + } + + func startAnimatingView() { + #if os(OSX) + animatedImageIndicatorView.animates = true + #else + animatedImageIndicatorView.startAnimating() + #endif + animatedImageIndicatorView.hidden = false + } + + func stopAnimatingView() { + #if os(OSX) + animatedImageIndicatorView.animates = false + #else + animatedImageIndicatorView.stopAnimating() + #endif + animatedImageIndicatorView.hidden = true + } +} From af6a500f63d15f7e362d16a13602d3c7eb0d9e87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20D=2E=20Moreira?= Date: Wed, 7 Sep 2016 12:02:12 +0200 Subject: [PATCH 3/6] Fixed tests --- .../ImageViewExtensionTests.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Tests/KingfisherTests/ImageViewExtensionTests.swift b/Tests/KingfisherTests/ImageViewExtensionTests.swift index a70ecacae..a95d206f3 100644 --- a/Tests/KingfisherTests/ImageViewExtensionTests.swift +++ b/Tests/KingfisherTests/ImageViewExtensionTests.swift @@ -383,15 +383,15 @@ class ImageViewExtensionTests: XCTestCase { } func testIndicatorViewExisting() { - imageView.kf_showIndicatorWhenLoading = true - XCTAssertNotNil(imageView.kf_indicator, "The indicator view should exist when showIndicatorWhenLoading is true") - - imageView.kf_showIndicatorWhenLoading = false - XCTAssertNil(imageView.kf_indicator, "The indicator view should be removed when showIndicatorWhenLoading set to false") + imageView.kf_indicatorType = .activity + XCTAssertNotNil(imageView.kf_indicator, "The indicator should exist when indicatorType is different than .none") + + imageView.kf_indicatorType = .none + XCTAssertNil(imageView.kf_indicator, "The indicator should be removed when indicatorType is .none") } func testIndicatorViewAnimating() { - imageView.kf_showIndicatorWhenLoading = true + imageView.kf_indicatorType = .activity let expectation = expectationWithDescription("wait for downloading image") @@ -403,11 +403,11 @@ class ImageViewExtensionTests: XCTestCase { let indicator = self.imageView.kf_indicator XCTAssertNotNil(indicator, "The indicator view should exist when showIndicatorWhenLoading is true") - XCTAssertFalse(indicator!.hidden, "The indicator should be shown and animating when loading") + XCTAssertFalse(indicator!.view.hidden, "The indicator should be shown and animating when loading") }) { (image, error, cacheType, imageURL) -> () in let indicator = self.imageView.kf_indicator - XCTAssertTrue(indicator!.hidden, "The indicator should stop and hidden after loading") + XCTAssertTrue(indicator!.view.hidden, "The indicator should stop and hidden after loading") expectation.fulfill() } From 126f42a27ebf6d72d83e0e1679f3f53e8ce3a115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20D=2E=20Moreira?= Date: Wed, 7 Sep 2016 12:34:14 +0200 Subject: [PATCH 4/6] Demos use a gif as the indicator --- Demo/Kingfisher-Demo/ViewController.swift | 6 +++++- Demo/Kingfisher-OSX-Demo/ViewController.swift | 7 ++++++- Kingfisher.xcodeproj/project.pbxproj | 8 ++++++++ images/loader.gif | Bin 0 -> 10302 bytes 4 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 images/loader.gif diff --git a/Demo/Kingfisher-Demo/ViewController.swift b/Demo/Kingfisher-Demo/ViewController.swift index e7181bc85..d548d278d 100644 --- a/Demo/Kingfisher-Demo/ViewController.swift +++ b/Demo/Kingfisher-Demo/ViewController.swift @@ -65,7 +65,11 @@ extension ViewController { let cell = collectionView.dequeueReusableCellWithReuseIdentifier("collectionViewCell", forIndexPath: indexPath) as! CollectionViewCell - cell.cellImageView.kf_showIndicatorWhenLoading = true + if let loaderPath = NSBundle.mainBundle().pathForResource("loader", ofType: "gif") { + if let loaderData = NSData(contentsOfFile: loaderPath) { + cell.cellImageView?.kf_indicatorType = .image(imageData: loaderData) + } + } let URL = NSURL(string: "https://raw.githubusercontent.com/onevcat/Kingfisher/master/images/kingfisher-\(indexPath.row + 1).jpg")! diff --git a/Demo/Kingfisher-OSX-Demo/ViewController.swift b/Demo/Kingfisher-OSX-Demo/ViewController.swift index 8aa763beb..577e84455 100644 --- a/Demo/Kingfisher-OSX-Demo/ViewController.swift +++ b/Demo/Kingfisher-OSX-Demo/ViewController.swift @@ -61,9 +61,14 @@ extension ViewController: NSCollectionViewDataSource { func collectionView(collectionView: NSCollectionView, itemForRepresentedObjectAtIndexPath indexPath: NSIndexPath) -> NSCollectionViewItem { let item = collectionView.makeItemWithIdentifier("Cell", forIndexPath: indexPath) + if let loaderPath = NSBundle.mainBundle().pathForResource("loader", ofType: "gif") { + if let loaderData = NSData(contentsOfFile: loaderPath) { + item.imageView?.kf_indicatorType = .image(imageData: loaderData) + } + } + let URL = NSURL(string: "https://raw.githubusercontent.com/onevcat/Kingfisher/master/images/kingfisher-\(indexPath.item + 1).jpg")! - item.imageView?.kf_showIndicatorWhenLoading = true item.imageView?.kf_setImageWithURL(URL, placeholderImage: nil, optionsInfo: nil, progressBlock: { receivedSize, totalSize in print("\(indexPath.item + 1): \(receivedSize)/\(totalSize)") diff --git a/Kingfisher.xcodeproj/project.pbxproj b/Kingfisher.xcodeproj/project.pbxproj index c78078245..56f633e9e 100644 --- a/Kingfisher.xcodeproj/project.pbxproj +++ b/Kingfisher.xcodeproj/project.pbxproj @@ -22,6 +22,8 @@ CD2C73541D7F040B00A1D819 /* Indicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD2C73531D7F040B00A1D819 /* Indicator.swift */; }; CD2C73551D7F040B00A1D819 /* Indicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD2C73531D7F040B00A1D819 /* Indicator.swift */; }; CD2C73561D7F040B00A1D819 /* Indicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD2C73531D7F040B00A1D819 /* Indicator.swift */; }; + CD2C736B1D80231E00A1D819 /* loader.gif in Resources */ = {isa = PBXBuildFile; fileRef = CD2C736A1D80231E00A1D819 /* loader.gif */; }; + CD2C736D1D80234F00A1D819 /* loader.gif in Resources */ = {isa = PBXBuildFile; fileRef = CD2C736C1D80234F00A1D819 /* loader.gif */; }; CD4593971D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */; }; CD4593981D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */; }; CD4593991D7EAB9900FD570E /* WrappedAssociatedObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */; }; @@ -275,6 +277,8 @@ A9E621E297FEFAD35D39C34E /* libPods-KingfisherTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-KingfisherTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; B6B5C590A36C8E84C5B16C3E /* Pods-KingfisherTests-tvOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KingfisherTests-tvOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-KingfisherTests-tvOS/Pods-KingfisherTests-tvOS.debug.xcconfig"; sourceTree = ""; }; CD2C73531D7F040B00A1D819 /* Indicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Indicator.swift; path = Sources/Indicator.swift; sourceTree = ""; }; + CD2C736A1D80231E00A1D819 /* loader.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = loader.gif; path = images/loader.gif; sourceTree = SOURCE_ROOT; }; + CD2C736C1D80234F00A1D819 /* loader.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = loader.gif; path = images/loader.gif; sourceTree = SOURCE_ROOT; }; CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WrappedAssociatedObjects.swift; path = Sources/WrappedAssociatedObjects.swift; sourceTree = ""; }; D10945EA1C526B6C001408EB /* Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Image.swift; path = Sources/Image.swift; sourceTree = ""; }; D10945EB1C526B6C001408EB /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ImageCache.swift; path = Sources/ImageCache.swift; sourceTree = ""; }; @@ -539,6 +543,7 @@ D12E0C8B1C47F91800AC98AD /* Kingfisher-Demo */ = { isa = PBXGroup; children = ( + CD2C736C1D80234F00A1D819 /* loader.gif */, D12E0C8C1C47F91800AC98AD /* AppDelegate.swift */, D12E0C8D1C47F91800AC98AD /* LaunchScreen.xib */, D12E0C8F1C47F91800AC98AD /* Main.storyboard */, @@ -566,6 +571,7 @@ D12E0CA61C47F92C00AC98AD /* Kingfisher-OSX-Demo */ = { isa = PBXGroup; children = ( + CD2C736A1D80231E00A1D819 /* loader.gif */, D12E0CA71C47F92C00AC98AD /* AppDelegate.swift */, D12E0CA81C47F92C00AC98AD /* Assets.xcassets */, D12E0CA91C47F92C00AC98AD /* Main.storyboard */, @@ -1002,6 +1008,7 @@ buildActionMask = 2147483647; files = ( D12E0CAF1C47F92C00AC98AD /* Assets.xcassets in Resources */, + CD2C736B1D80231E00A1D819 /* loader.gif in Resources */, D12E0CB11C47F92C00AC98AD /* Cell.xib in Resources */, D12E0CB01C47F92C00AC98AD /* Main.storyboard in Resources */, ); @@ -1070,6 +1077,7 @@ buildActionMask = 2147483647; files = ( D12E0C991C47F91800AC98AD /* Images.xcassets in Resources */, + CD2C736D1D80234F00A1D819 /* loader.gif in Resources */, D12E0C961C47F91800AC98AD /* LaunchScreen.xib in Resources */, D12E0C971C47F91800AC98AD /* Main.storyboard in Resources */, ); diff --git a/images/loader.gif b/images/loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..ed2c01b5ef4caf0cf35f0f78481b2a88850664e6 GIT binary patch literal 10302 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 TsmfT7$m-!rRu~!t*z!LB;Sk^w literal 0 HcmV?d00001 From 031ea6438541d614228eba65648623e876544b90 Mon Sep 17 00:00:00 2001 From: onevcat Date: Mon, 12 Sep 2016 16:04:04 +0900 Subject: [PATCH 5/6] Back compatible for earlier versions --- Demo/Kingfisher-Demo/ViewController.swift | 10 +---- Sources/ImageView+Kingfisher.swift | 49 ++++++++++++++++++----- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/Demo/Kingfisher-Demo/ViewController.swift b/Demo/Kingfisher-Demo/ViewController.swift index d548d278d..cfed8e145 100644 --- a/Demo/Kingfisher-Demo/ViewController.swift +++ b/Demo/Kingfisher-Demo/ViewController.swift @@ -64,16 +64,10 @@ extension ViewController { override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCellWithReuseIdentifier("collectionViewCell", forIndexPath: indexPath) as! CollectionViewCell - - if let loaderPath = NSBundle.mainBundle().pathForResource("loader", ofType: "gif") { - if let loaderData = NSData(contentsOfFile: loaderPath) { - cell.cellImageView?.kf_indicatorType = .image(imageData: loaderData) - } - } - + let URL = NSURL(string: "https://raw.githubusercontent.com/onevcat/Kingfisher/master/images/kingfisher-\(indexPath.row + 1).jpg")! - + cell.cellImageView.kf_showIndicatorWhenLoading = true cell.cellImageView.kf_setImageWithURL(URL, placeholderImage: nil, optionsInfo: [.Transition(ImageTransition.Fade(1))], progressBlock: { receivedSize, totalSize in diff --git a/Sources/ImageView+Kingfisher.swift b/Sources/ImageView+Kingfisher.swift index ddacd7b79..63d80036e 100644 --- a/Sources/ImageView+Kingfisher.swift +++ b/Sources/ImageView+Kingfisher.swift @@ -182,16 +182,21 @@ extension ImageView { */ extension ImageView { public enum IndicatorType { - case none // no indicator - case custom(indicator: Indicator) // user custom indicator - case activity // activity indicator - case image(imageData: NSData) // supports gif + /// No indicator. + case None + /// Use system activity indicator. + case Activity + /// Use an image as indicator. GIF is supported. + case Image(imageData: NSData) + /// Use a custom indicator, which conforms to the `Indicator` protocol. + case Custom(indicator: Indicator) } } // MARK: - Associated Object private var lastURLKey: Void? private var indicatorKey: Void? +private var showIndicatorWhenLoadingKey: Void? private var indicatorTypeKey: Void? private var imageTaskKey: Void? @@ -205,24 +210,46 @@ extension ImageView { setAssociatedObject(self, value: URL, associativeKey: &lastURLKey) } + + /// Whether show an animating activity indicator when the image view is loading an image or not. + /// Default is false. + public var kf_showIndicatorWhenLoading: Bool { + get { + switch kf_indicatorType { + case .None: + return false + case .Activity: fallthrough + case .Image(_): fallthrough + case .Custom(_): return true + } + } + + set { + if kf_showIndicatorWhenLoading == newValue { + return + } else { + kf_indicatorType = .Activity + } + } + } /// Holds which indicator type is going to be used. - /// Default is .none + /// Default is .None public var kf_indicatorType: IndicatorType { get { let indicator: IndicatorType? = getAssociatedObject(self, associativeKey: &indicatorTypeKey) - return indicator ?? .none + return indicator ?? .None } set { switch newValue { - case .none: + case .None: kf_indicator = nil - case .activity: + case .Activity: kf_indicator = ActivityIndicator() - case .image(let data): + case .Image(let data): kf_indicator = ImageIndicator(imageData: data) - case .custom(let indicator): + case .Custom(let indicator): kf_indicator = indicator } @@ -232,7 +259,7 @@ extension ImageView { /// `kf_indicator` holds any type that conforms to the protocol `Indicator`. /// The protocol `Indicator` has a `view` property that will be shown when loading an image. - /// Everything will be `nil` if `kf_indicatorType` is .none. + /// Everything will be `nil` if `kf_indicatorType` is .None. public private(set) var kf_indicator: Indicator? { get { let indicator: (Indicator?)? = getAssociatedObject(self, associativeKey: &indicatorKey) From 841c6b6eb9fff7fcf281a862ffd2d021dc2e5ac3 Mon Sep 17 00:00:00 2001 From: onevcat Date: Mon, 12 Sep 2016 16:08:53 +0900 Subject: [PATCH 6/6] Fix tests --- Tests/KingfisherTests/ImageViewExtensionTests.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Tests/KingfisherTests/ImageViewExtensionTests.swift b/Tests/KingfisherTests/ImageViewExtensionTests.swift index a95d206f3..ffd89e214 100644 --- a/Tests/KingfisherTests/ImageViewExtensionTests.swift +++ b/Tests/KingfisherTests/ImageViewExtensionTests.swift @@ -383,15 +383,15 @@ class ImageViewExtensionTests: XCTestCase { } func testIndicatorViewExisting() { - imageView.kf_indicatorType = .activity - XCTAssertNotNil(imageView.kf_indicator, "The indicator should exist when indicatorType is different than .none") + imageView.kf_indicatorType = .Activity + XCTAssertNotNil(imageView.kf_indicator, "The indicator should exist when indicatorType is different than .None") - imageView.kf_indicatorType = .none - XCTAssertNil(imageView.kf_indicator, "The indicator should be removed when indicatorType is .none") + imageView.kf_indicatorType = .None + XCTAssertNil(imageView.kf_indicator, "The indicator should be removed when indicatorType is .None") } func testIndicatorViewAnimating() { - imageView.kf_indicatorType = .activity + imageView.kf_indicatorType = .Activity let expectation = expectationWithDescription("wait for downloading image")