Browse Source

Fix Sendable warnings in Xcode 26

- Add Sendable constraints to generic type parameters where needed
- DiskStorage.Backend: Add `where T: Sendable` constraint
- MemoryStorage.Backend: Keep existing `where T: Sendable` constraint
- Mark both Backend classes as final while keeping @unchecked Sendable
- Fix SwiftUI components to properly handle Sendable requirements:
  - Add Sendable constraint to KFImageHoldingView protocol conformances
  - Update ImageBinder, Context, and Renderer with proper constraints
- Maintain API compatibility by adding constraints only where necessary
onevcat 7 months ago
parent
commit
4a99f5625d

+ 1 - 1
Sources/Cache/DiskStorage.swift

@@ -43,7 +43,7 @@ public enum DiskStorage {
     /// ``DiskStorage/Config`` value or by modifying the ``DiskStorage/Backend/config`` property after it has been
     /// created. The ``DiskStorage/Backend`` will use the file's attributes to keep track of a file for its expiration
     /// or size limitation.
-    public class Backend<T: DataTransformable>: @unchecked Sendable {
+    public final class Backend<T: DataTransformable>: @unchecked Sendable where T: Sendable {
         
         private let propertyQueue = DispatchQueue(label: "com.onevcat.kingfisher.DiskStorage.Backend.propertyQueue")
         

+ 1 - 1
Sources/Cache/MemoryStorage.swift

@@ -51,7 +51,7 @@ public enum MemoryStorage {
     /// The `MemoryStorage` also includes a scheduled self-cleaning task to evict expired items from memory.
     ///
     /// > This class is thready safe.
-    public class Backend<T: CacheCostCalculable>: @unchecked Sendable {
+    public final class Backend<T: CacheCostCalculable>: @unchecked Sendable where T: Sendable {
         
         let storage = NSCache<NSString, StorageObject<T>>()
 

+ 1 - 1
Sources/SwiftUI/ImageBinder.swift

@@ -65,7 +65,7 @@ extension KFImage {
             }
         }
 
-        func start<HoldingView: KFImageHoldingView>(context: Context<HoldingView>) {
+        func start<HoldingView: KFImageHoldingView>(context: Context<HoldingView>) where HoldingView: Sendable {
             guard let source = context.source else {
                 CallbackQueueMain.currentOrAsync {
                     context.onFailureDelegate.call(KingfisherError.imageSettingError(reason: .emptySource))

+ 1 - 1
Sources/SwiftUI/ImageContext.swift

@@ -30,7 +30,7 @@ import Combine
 
 @available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
 extension KFImage {
-    public class Context<HoldingView: KFImageHoldingView>: @unchecked Sendable {
+    public class Context<HoldingView: KFImageHoldingView>: @unchecked Sendable where HoldingView: Sendable {
         
         private let propertyQueue = DispatchQueue(label: "com.onevcat.Kingfisher.KFImageContextPropertyQueue")
         

+ 1 - 1
Sources/SwiftUI/KFAnimatedImage.swift

@@ -57,7 +57,7 @@ typealias KFCrossPlatformViewRepresentable = UIViewRepresentable
 
 /// A wrapped `UIViewRepresentable` of `AnimatedImageView`
 @available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
-public struct KFAnimatedImageViewRepresenter: KFCrossPlatformViewRepresentable, KFImageHoldingView {
+public struct KFAnimatedImageViewRepresenter: KFCrossPlatformViewRepresentable, KFImageHoldingView, Sendable {
     public typealias RenderingView = AnimatedImageView
     public static func created(from image: KFCrossPlatformImage?, context: KFImage.Context<Self>) -> KFAnimatedImageViewRepresenter {
         KFAnimatedImageViewRepresenter(image: image, context: context)

+ 1 - 1
Sources/SwiftUI/KFImageProtocol.swift

@@ -37,7 +37,7 @@ import Combine
 @available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
 @MainActor
 public protocol KFImageProtocol: View, KFOptionSetter {
-    associatedtype HoldingView: KFImageHoldingView
+    associatedtype HoldingView: KFImageHoldingView & Sendable
     var context: KFImage.Context<HoldingView> { get set }
     init(context: KFImage.Context<HoldingView>)
 }

+ 1 - 1
Sources/SwiftUI/KFImageRenderer.swift

@@ -31,7 +31,7 @@ import Combine
 /// 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 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
-struct KFImageRenderer<HoldingView> : View where HoldingView: KFImageHoldingView {
+struct KFImageRenderer<HoldingView> : View where HoldingView: KFImageHoldingView & Sendable {
     
     @StateObject var binder: KFImage.ImageBinder = .init()
     let context: KFImage.Context<HoldingView>