Răsfoiți Sursa

SPM support for SwiftUI

onevcat 6 ani în urmă
părinte
comite
886c8b332f

+ 4 - 2
Kingfisher.xcodeproj/project.pbxproj

@@ -8,6 +8,7 @@
 
 /* Begin PBXBuildFile section */
 		4B10480D216F157000300C61 /* ImageDataProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B10480C216F157000300C61 /* ImageDataProcessor.swift */; };
+		4B24D1762314CDDA00497D39 /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B24D1752314CDDA00497D39 /* Delegate.swift */; };
 		4B46CC5F217449C600D90C4A /* MemoryStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B46CC5E217449C600D90C4A /* MemoryStorage.swift */; };
 		4B46CC64217449E000D90C4A /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B46CC63217449E000D90C4A /* Storage.swift */; };
 		4B46CC6921744AC500D90C4A /* DiskStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B46CC6821744AC500D90C4A /* DiskStorage.swift */; };
@@ -89,7 +90,6 @@
 		D1839845216E333E003927D3 /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1839844216E333E003927D3 /* Delegate.swift */; };
 		D186696D21834261002B502E /* ImageDrawingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D186696C21834261002B502E /* ImageDrawingTests.swift */; };
 		D19ADD0C23099E3B00D20B28 /* Kingfisher.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1ED2D351AD2D09F00CFC3EB /* Kingfisher.framework */; };
-		D19ADD0D23099E5E00D20B28 /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1839844216E333E003927D3 /* Delegate.swift */; };
 		D1A1CC9A219FAB4B00263AD8 /* Source.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A1CC99219FAB4B00263AD8 /* Source.swift */; };
 		D1A1CC9F21A0F98600263AD8 /* ImageDataProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A1CC9E21A0F98600263AD8 /* ImageDataProviderTests.swift */; };
 		D1A37BDE215D34E8009B39B7 /* ImageDrawing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1A37BDD215D34E8009B39B7 /* ImageDrawing.swift */; };
@@ -126,6 +126,7 @@
 		185218B51CC07F8300BD58DE /* NSButtonExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSButtonExtensionTests.swift; sourceTree = "<group>"; };
 		4B10480C216F157000300C61 /* ImageDataProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDataProcessor.swift; sourceTree = "<group>"; };
 		4B164ACE1B8D554200768EC6 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
+		4B24D1752314CDDA00497D39 /* Delegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Delegate.swift; sourceTree = "<group>"; };
 		4B3E714D1B01FEB200F5AAED /* WatchKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WatchKit.framework; path = System/Library/Frameworks/WatchKit.framework; sourceTree = SDKROOT; };
 		4B46CC5E217449C600D90C4A /* MemoryStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryStorage.swift; sourceTree = "<group>"; };
 		4B46CC63217449E000D90C4A /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = "<group>"; };
@@ -644,6 +645,7 @@
 		D1F7607423097532000C5269 /* SwiftUI */ = {
 			isa = PBXGroup;
 			children = (
+				4B24D1752314CDDA00497D39 /* Delegate.swift */,
 				D1F7607523097532000C5269 /* ImageBinder.swift */,
 				D1F7607623097532000C5269 /* KFImage.swift */,
 			);
@@ -900,7 +902,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				D19ADD0D23099E5E00D20B28 /* Delegate.swift in Sources */,
+				4B24D1762314CDDA00497D39 /* Delegate.swift in Sources */,
 				D1F7607823097533000C5269 /* KFImage.swift in Sources */,
 				D1F7607723097533000C5269 /* ImageBinder.swift in Sources */,
 			);

+ 8 - 1
Package.swift

@@ -5,13 +5,20 @@ let package = Package(
     name: "Kingfisher",
     platforms: [.iOS(.v10), .macOS(.v10_12), .tvOS(.v10), .watchOS(.v3)],
     products: [
-        .library(name: "Kingfisher", targets: ["Kingfisher"])
+        .library(name: "Kingfisher", targets: ["Kingfisher"]),
+        .library(name: "KingfisherSwiftUI", targets: ["KingfisherSwiftUI"])
     ],
     targets: [
         .target(
             name: "Kingfisher",
             path: "Sources",
             exclude: ["SwiftUI"]
+        ),
+        .target(
+            name: "KingfisherSwiftUI",
+            dependencies: ["Kingfisher"],
+            path: "Sources",
+            sources: ["SwiftUI"]
         )
     ]
 )

+ 53 - 0
Sources/SwiftUI/Delegate.swift

@@ -0,0 +1,53 @@
+//
+//  Delegate.swift
+//  Kingfisher
+//
+//  Created by onevcat on 2018/10/10.
+//
+//  Copyright (c) 2019 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
+
+/// A delegate helper type to "shadow" weak `self`, to prevent creating an unexpected retain cycle.
+class Delegate<Input, Output> {
+    init() {}
+    
+    private var block: ((Input) -> Output?)?
+    
+    func delegate<T: AnyObject>(on target: T, block: ((T, Input) -> Output)?) {
+        // The `target` is weak inside block, so you do not need to worry about it in the caller side.
+        self.block = { [weak target] input in
+            guard let target = target else { return nil }
+            return block?(target, input)
+        }
+    }
+    
+    func call(_ input: Input) -> Output? {
+        return block?(input)
+    }
+}
+
+extension Delegate where Input == Void {
+    // To make syntax better for `Void` input.
+    func call() -> Output? {
+        return call(())
+    }
+}

+ 1 - 0
Sources/SwiftUI/ImageBinder.swift

@@ -28,6 +28,7 @@ import Combine
 import SwiftUI
 import Kingfisher
 
+@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
 extension KFImage {
 
     /// Represents a binder for `KFImage`. It takes responsibility as an `ObjectBinding` and performs

+ 5 - 0
Sources/SwiftUI/KFImage.swift

@@ -28,6 +28,7 @@ import SwiftUI
 import Combine
 import Kingfisher
 
+@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
 extension Image {
     // Creates an SwiftUI.Image with either UIImage or NSImage.
     init(crossPlatformImage: KFCrossPlatformImage) {
@@ -41,6 +42,7 @@ extension Image {
 
 /// A Kingfisher compatible SwiftUI `View` to load an image from a `Source`.
 /// Declaring a `KFImage` in a `View`'s body to trigger loading from the given `Source`.
+@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
 public struct KFImage: View {
 
     /// An image binder that manages loading and cancelling image related task.
@@ -97,6 +99,7 @@ public struct KFImage: View {
     }
 }
 
+@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
 extension KFImage {
 
     /// Configures current image with a `block`. This block will be lazily applied when creating the final `Image`.
@@ -147,6 +150,7 @@ extension KFImage {
     }
 }
 
+@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
 extension KFImage {
 
     /// Sets the action to perform when the image setting fails.
@@ -178,6 +182,7 @@ extension KFImage {
 }
 
 #if DEBUG
+@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
 struct KFImage_Previews : PreviewProvider {
     static var previews: some View {
         Group {