Selaa lähdekoodia

Wrapped associated objects

João D. Moreira 9 vuotta sitten
vanhempi
commit
d85613800a

+ 10 - 0
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 = "<group>"; };
 		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 = "<group>"; };
+		CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WrappedAssociatedObjects.swift; path = Sources/WrappedAssociatedObjects.swift; sourceTree = "<group>"; };
 		D10945EA1C526B6C001408EB /* Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Image.swift; path = Sources/Image.swift; sourceTree = "<group>"; };
 		D10945EB1C526B6C001408EB /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ImageCache.swift; path = Sources/ImageCache.swift; sourceTree = "<group>"; };
 		D10945EC1C526B6C001408EB /* ImageDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ImageDownloader.swift; path = Sources/ImageDownloader.swift; sourceTree = "<group>"; };
@@ -459,6 +464,7 @@
 				D10945F51C526B6C001408EB /* ThreadHelper.swift */,
 				D10945F61C526B6C001408EB /* UIButton+Kingfisher.swift */,
 				182FFF771CC9ACBA004B728D /* NSButton+Kingfisher.swift */,
+				CD4593961D7EAB9900FD570E /* WrappedAssociatedObjects.swift */,
 			);
 			name = Sources;
 			sourceTree = "<group>";
@@ -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 */,

+ 8 - 8
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

+ 8 - 8
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)
     }
 }
 

+ 9 - 9
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)
     }
 }
 

+ 8 - 8
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)
     }
 }
 

+ 45 - 0
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<T> {
+    let value: T
+    init(_ x: T) {
+        value = x
+    }
+}
+
+private func wrap<T>(x: T) -> Wrapper<T> {
+    return Wrapper(x)
+}
+
+func setAssociatedObject<T>(object: AnyObject, value: T, associativeKey: UnsafePointer<Void>, 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<T>(object: AnyObject, associativeKey: UnsafePointer<Void>) -> T? {
+
+    let v = objc_getAssociatedObject(object, associativeKey)
+
+    if let v = v as? T {
+        return v
+    } else if let v = v as? Wrapper<T> {
+        return v.value
+    } else {
+        return nil
+    }
+}