Bläddra i källkod

Merge pull request #2259 from onevcat/xcode-16

Xcode 16 Support
Wei Wang 1 år sedan
förälder
incheckning
dbcb98dae0

+ 9 - 3
Kingfisher.xcodeproj/project.pbxproj

@@ -761,7 +761,7 @@
 			attributes = {
 				BuildIndependentTargetsInParallel = YES;
 				LastSwiftUpdateCheck = 0720;
-				LastUpgradeCheck = 1500;
+				LastUpgradeCheck = 1600;
 				ORGANIZATIONNAME = "Wei Wang";
 				TargetAttributes = {
 					D1ED2D341AD2D09F00CFC3EB = {
@@ -1001,7 +1001,7 @@
 				SUPPORTED_PLATFORMS = "watchsimulator iphonesimulator appletvsimulator watchos appletvos iphoneos macosx";
 				SWIFT_INSTALL_OBJC_HEADER = NO;
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
-				SWIFT_VERSION = 5.0;
+				SWIFT_VERSION = 6.0;
 				TARGETED_DEVICE_FAMILY = "1,2,3,4";
 				TVOS_DEPLOYMENT_TARGET = 13.0;
 				WATCHOS_DEPLOYMENT_TARGET = 6.0;
@@ -1061,7 +1061,7 @@
 				SWIFT_COMPILATION_MODE = wholemodule;
 				SWIFT_INSTALL_OBJC_HEADER = NO;
 				SWIFT_OPTIMIZATION_LEVEL = "-O";
-				SWIFT_VERSION = 5.0;
+				SWIFT_VERSION = 6.0;
 				TARGETED_DEVICE_FAMILY = "1,2,3,4";
 				TVOS_DEPLOYMENT_TARGET = 13.0;
 				WATCHOS_DEPLOYMENT_TARGET = 6.0;
@@ -1092,6 +1092,7 @@
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 2739;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_MODULE_VERIFIER = YES;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
 				GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
 				GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
@@ -1113,6 +1114,7 @@
 					"@executable_path/Frameworks",
 					"@loader_path/Frameworks",
 				);
+				MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11";
 				OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-expression-type-checking=150";
 				PRODUCT_BUNDLE_IDENTIFIER = "com.onevcat.$(PRODUCT_NAME:rfc1034identifier)";
 				PRODUCT_BUNDLE_PACKAGE_TYPE = FMWK;
@@ -1154,6 +1156,7 @@
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 2739;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
+				ENABLE_MODULE_VERIFIER = YES;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
 				GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
 				GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
@@ -1175,6 +1178,7 @@
 					"@executable_path/Frameworks",
 					"@loader_path/Frameworks",
 				);
+				MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11";
 				OTHER_SWIFT_FLAGS = "";
 				PRODUCT_BUNDLE_IDENTIFIER = "com.onevcat.$(PRODUCT_NAME:rfc1034identifier)";
 				PRODUCT_BUNDLE_PACKAGE_TYPE = FMWK;
@@ -1218,6 +1222,7 @@
 				SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
 				SWIFT_OBJC_BRIDGING_HEADER = "Tests/KingfisherTests/KingfisherTests-Bridging-Header.h";
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 5.0;
 				TARGETED_DEVICE_FAMILY = "1,2,3,4,7";
 			};
 			name = Debug;
@@ -1245,6 +1250,7 @@
 				SWIFT_COMPILATION_MODE = wholemodule;
 				SWIFT_OBJC_BRIDGING_HEADER = "Tests/KingfisherTests/KingfisherTests-Bridging-Header.h";
 				SWIFT_OPTIMIZATION_LEVEL = "-O";
+				SWIFT_VERSION = 5.0;
 				TARGETED_DEVICE_FAMILY = "1,2,3,4,7";
 			};
 			name = Release;

+ 1 - 1
Kingfisher.xcodeproj/xcshareddata/xcschemes/Kingfisher.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1500"
+   LastUpgradeVersion = "1600"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 4 - 0
Sources/Cache/ImageCache.swift

@@ -835,7 +835,11 @@ open class ImageCache: @unchecked Sendable {
         cleanExpiredDiskCache {
             Task {
                 guard let bgTask = await taskActor.value, bgTask != .invalid else { return }
+                #if swift(>=6)
+                sharedApplication.endBackgroundTask(bgTask)
+                #else
                 await sharedApplication.endBackgroundTask(bgTask)
+                #endif
                 await taskActor.setValue(.invalid)
             }
         }

+ 5 - 3
Sources/General/ImageSource/PHPickerResultImageDataProvider.swift

@@ -28,7 +28,7 @@ import Foundation
 
 #if os(iOS) || os(macOS) || os(visionOS)
 
-import PhotosUI
+@preconcurrency import PhotosUI
 
 /// A data provider to provide image data from a given `PHPickerResult`.
 @available(iOS 14.0, macOS 13.0, *)
@@ -37,6 +37,8 @@ public struct PHPickerResultImageDataProvider: ImageDataProvider {
     /// The possible error might be caused by the `PHPickerResultImageDataProvider`.
     /// - invalidImage: The retrieved image is invalid.
     public enum PHPickerResultImageDataProviderError: Error {
+        /// An error happens during picking up image through the item provider of `PHPickerResult`.
+        case pickerProviderError(Error)
         /// The retrieved image is invalid.
         case invalidImage
     }
@@ -64,10 +66,10 @@ public struct PHPickerResultImageDataProvider: ImageDataProvider {
         self.contentType = contentType
     }
 
-    public func data(handler: @escaping (Result<Data, Error>) -> Void) {
+    public func data(handler: @escaping @Sendable (Result<Data, Error>) -> Void) {
         pickerResult.itemProvider.loadDataRepresentation(forTypeIdentifier: contentType.identifier) { data, error in
             if let error {
-                handler(.failure(error))
+                handler(.failure(PHPickerResultImageDataProviderError.pickerProviderError(error)))
                 return
             }
 

+ 2 - 2
Sources/General/KF.swift

@@ -148,8 +148,8 @@ extension KF {
             }
         }
 
-        private var progressBlock: DownloadProgressBlock {
-            { self.onProgressDelegate(($0, $1)) }
+        private var progressBlock: DownloadProgressBlock? {
+            onProgressDelegate.isSet ? { self.onProgressDelegate(($0, $1)) } : nil
         }
     }
 }

+ 1 - 0
Sources/General/KFOptionsSetter.swift

@@ -33,6 +33,7 @@ import UIKit
 #endif
 
 /// A protocol that Kingfisher can use to perform chained setting in builder pattern.
+@MainActor
 public protocol KFOptionSetter {
     var options: KingfisherParsedOptionsInfo { get nonmutating set }
 

+ 1 - 1
Sources/General/KingfisherManager.swift

@@ -922,7 +922,7 @@ class CacheCallbackCoordinator: @unchecked Sendable {
     private let stateQueue: DispatchQueue
     private var threadSafeState: State = .idle
 
-    private (set) var state: State {
+    private(set) var state: State {
         set { stateQueue.sync { threadSafeState = newValue } }
         get { stateQueue.sync { threadSafeState } }
     }

+ 8 - 8
Sources/General/KingfisherOptionsInfo.swift

@@ -482,15 +482,15 @@ class ImageLoadingProgressSideEffect: DataReceivingSideEffect, @unchecked Sendab
     }
 
     func onDataReceived(_ session: URLSession, task: SessionDataTask, data: Data) {
-        guard self.onShouldApply() else { return }
-        guard let expectedContentLength = task.task.response?.expectedContentLength,
-                  expectedContentLength != -1 else
-        {
-            return
-        }
-
-        let dataLength = Int64(task.mutableData.count)
         DispatchQueue.main.async {
+            guard self.onShouldApply() else { return }
+            guard let expectedContentLength = task.task.response?.expectedContentLength,
+                      expectedContentLength != -1 else
+            {
+                return
+            }
+
+            let dataLength = Int64(task.mutableData.count)
             self.block(dataLength, expectedContentLength)
         }
     }

+ 3 - 3
Sources/Image/Image.swift

@@ -45,9 +45,9 @@ import ImageIO
 import UniformTypeIdentifiers
 #endif
 
-private let animatedImageDataKey = malloc(1)!
-private let imageFrameCountKey = malloc(1)!
-private let imageSourceKey = malloc(1)!
+nonisolated(unsafe) private let animatedImageDataKey = malloc(1)!
+nonisolated(unsafe) private let imageFrameCountKey = malloc(1)!
+nonisolated(unsafe) private let imageSourceKey = malloc(1)!
 
 // MARK: - Image Properties
 extension KingfisherWrapper where Base: KFCrossPlatformImage {

+ 1 - 1
Sources/Networking/SessionDelegate.swift

@@ -30,7 +30,7 @@ import Foundation
 ///
 /// It also behaves like a task manager for downloading.
 @objc(KFSessionDelegate) // Fix for ObjC header name conflicting. https://github.com/onevcat/Kingfisher/issues/1530
-open class SessionDelegate: NSObject {
+open class SessionDelegate: NSObject, @unchecked Sendable {
 
     typealias SessionChallengeFunc = (
         URLSession,

+ 2 - 0
Sources/SwiftUI/KFImageProtocol.swift

@@ -35,6 +35,7 @@ import Combine
 /// ``KFAnimatedImage`` conform this type and should be used in your app to represent an image view with network and
 /// cache support in SwiftUI.
 @available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
+@MainActor
 public protocol KFImageProtocol: View, KFOptionSetter {
     associatedtype HoldingView: KFImageHoldingView
     var context: KFImage.Context<HoldingView> { get set }
@@ -103,6 +104,7 @@ extension KFImageProtocol {
 }
 
 @available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
+@MainActor
 public protocol KFImageHoldingView: View {
     associatedtype RenderingView
     static func created(from image: KFCrossPlatformImage?, context: KFImage.Context<Self>) -> Self

+ 1 - 1
Sources/Utility/CallbackQueue.swift

@@ -85,7 +85,7 @@ enum CallbackQueueMain {
 
 extension MainActor {
     @_unavailableFromAsync
-    static func runUnsafely<T>(_ body: @MainActor () throws -> T) rethrows -> T {
+    static func runUnsafely<T: Sendable>(_ body: @MainActor () throws -> T) rethrows -> T {
 #if swift(>=5.10)
         return try MainActor.assumeIsolated(body)
 #else

+ 4 - 0
Sources/Utility/Delegate.swift

@@ -110,6 +110,10 @@ public class Delegate<Input, Output>: @unchecked Sendable {
     public func callAsync(_ input: Input) async -> Output? {
         return await asyncBlock?(input)
     }
+    
+    public var isSet: Bool {
+        block != nil || asyncBlock != nil
+    }
 }
 
 extension Delegate where Input == Void {

+ 4 - 0
Sources/Utility/DisplayLink.swift

@@ -52,7 +52,11 @@ extension UIView {
     }
 }
 
+#if swift(>=6)
+extension CADisplayLink: DisplayLinkCompatible, @retroactive @unchecked Sendable {}
+#else
 extension CADisplayLink: DisplayLinkCompatible, @unchecked Sendable {}
+#endif
 
 #else
 extension NSView {

+ 6 - 1
Tests/KingfisherTests/DiskStorageTests.swift

@@ -27,7 +27,12 @@
 import XCTest
 @testable import Kingfisher
 
-extension String: DataTransformable {
+#if swift(>=6)
+extension String: @retroactive DataTransformable { }
+#else
+extension String: DataTransformable { }
+#endif
+extension String {
     public func toData() throws -> Data {
         return data(using: .utf8)!
     }

+ 1 - 1
Tests/KingfisherTests/ImageDownloaderTests.swift

@@ -586,7 +586,7 @@ class ImageDownloaderTests: XCTestCase {
     
     
     func testSessionDelegate() {
-        class ExtensionDelegate: SessionDelegate {
+        class ExtensionDelegate: SessionDelegate, @unchecked Sendable {
             //'exp' only for test
             public let exp: XCTestExpectation
             init(_ expectation:XCTestExpectation) {

+ 4 - 0
Tests/KingfisherTests/ImageViewExtensionTests.swift

@@ -922,4 +922,8 @@ class ImageViewExtensionTests: XCTestCase {
 
 }
 
+#if swift(>=6)
+extension KFCrossPlatformView: @retroactive Placeholder {}
+#else
 extension KFCrossPlatformView: Placeholder {}
+#endif

+ 7 - 1
Tests/KingfisherTests/MemoryStorageTests.swift

@@ -27,12 +27,18 @@
 import XCTest
 @testable import Kingfisher
 
-extension Int: CacheCostCalculable {
+extension Int {
     public var cacheCost: Int {
         return 1
     }
 }
 
+#if swift(>=6)
+extension Int: @retroactive CacheCostCalculable { }
+#else
+extension Int: CacheCostCalculable { }
+#endif
+
 class MemoryStorageTests: XCTestCase {
 
     var storage: MemoryStorage.Backend<Int>!

+ 4 - 2
fastlane/Fastfile

@@ -14,9 +14,9 @@ platform :ios do
     
   lane :test_ci do
     if ENV["DESTINATION"].include? "watchOS" then
-        build(destination: ENV["DESTINATION"])
+        build(destination: ENV["DESTINATION"], swift_version: "5.0")
     else
-        test(destination: ENV["DESTINATION"])
+        test(destination: ENV["DESTINATION"], swift_version: "5.0")
     end
   end
 
@@ -24,6 +24,7 @@ platform :ios do
     scan(
       scheme: "Kingfisher", 
       clean: true, 
+      xcargs: "SWIFT_VERSION=#{options[:swift_version]}",
       destination: options[:destination]
     )
   end
@@ -33,6 +34,7 @@ platform :ios do
       workspace: "Kingfisher.xcworkspace",
       configuration: "Debug",
       scheme: "Kingfisher",
+      xcargs: "SWIFT_VERSION=#{options[:swift_version]}",
       destination: options[:destination]
     )
   end