From 33ae71578a996007a65f6dd684fd7a25e3072fa5 Mon Sep 17 00:00:00 2001 From: Dave Camp Date: Wed, 14 May 2025 09:11:12 -0700 Subject: [PATCH] Updates for Swift 6.0 Updated to Gauntlet 2.2.0. Changed public types to Sendable. --- .../xcshareddata/swiftpm/Package.resolved | 7 ++++--- Package.swift | 10 +++++----- Sources/Cache/Cache.swift | 2 +- Sources/Cache/CacheConfig.swift | 2 +- Sources/Cache/CacheEvent.swift | 2 +- Sources/Cache/CacheKey.swift | 2 +- Sources/Cache/CacheLayer/MemoryCacheLayer.swift | 12 ++++++------ Sources/Cache/CacheLocation.swift | 2 +- Sources/Cache/CachePolicy.swift | 2 +- Sources/DemoApp/DemoApp.xcodeproj/project.pbxproj | 10 +++++----- .../xcshareddata/xcschemes/DemoApp.xcscheme | 2 +- Sources/DemoApp/DemoApp/SampleModel.swift | 15 ++++++++++----- Tests/CacheTests/CacheLocationTests.swift | 2 +- Tests/CacheTests/CacheTests.swift | 2 +- Tests/CacheTests/CodableFileTests.swift | 2 +- Tests/CacheTests/MemoryCacheLayerTests.swift | 2 +- Tests/CacheTests/MockCacheLayer.swift | 2 +- 17 files changed, 42 insertions(+), 36 deletions(-) diff --git a/Cache.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Cache.xcworkspace/xcshareddata/swiftpm/Package.resolved index d0b6806..93166e0 100644 --- a/Cache.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Cache.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,14 +1,15 @@ { + "originHash" : "be552bbcd2502ae6b4482df0d4c1d8ef4e5dae7081c7e96fa228793c10612d56", "pins" : [ { "identity" : "gauntlet-ios", "kind" : "remoteSourceControl", "location" : "https://github.com/krogerco/Gauntlet-iOS.git", "state" : { - "revision" : "4a4fe12bb927e775112c97686f57c52392d72ae1", - "version" : "1.1.0" + "revision" : "028896ab3b1ed89b185e890e67cd4635496acb1e", + "version" : "2.2.0" } } ], - "version" : 2 + "version" : 3 } diff --git a/Package.swift b/Package.swift index 1184f1a..c95efe9 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.7 +// swift-tools-version: 6.0 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -6,8 +6,8 @@ import PackageDescription let package = Package( name: "Cache", platforms: [ - .iOS(.v14), - .macOS(.v12) + .iOS(.v16), + .macOS(.v13) ], products: [ .library( @@ -15,7 +15,7 @@ let package = Package( targets: ["Cache"]) ], dependencies: [ - .package(url: "https://github.com/krogerco/Gauntlet-iOS.git", from: Version(1, 0, 0)) + .package(url: "https://github.com/krogerco/Gauntlet-iOS.git", from: "2.2.0") ], targets: [ .target(name: "Cache"), @@ -23,7 +23,7 @@ let package = Package( name: "CacheTests", dependencies: [ .byName(name: "Cache"), - .product(name: "Gauntlet", package: "Gauntlet-iOS") + .product(name: "GauntletLegacy", package: "Gauntlet-iOS") ] ) ] diff --git a/Sources/Cache/Cache.swift b/Sources/Cache/Cache.swift index 46e191a..9864cae 100644 --- a/Sources/Cache/Cache.swift +++ b/Sources/Cache/Cache.swift @@ -26,7 +26,7 @@ import Foundation typealias EventPublisher = PassthroughSubject /// A memory based cache with configurable policies and optional persistence. -public final class Cache { +public final class Cache: @unchecked Sendable { let lock = NSRecursiveLock() let layer: MemoryCacheLayer let identifier: String diff --git a/Sources/Cache/CacheConfig.swift b/Sources/Cache/CacheConfig.swift index 86b11cc..1cfae83 100644 --- a/Sources/Cache/CacheConfig.swift +++ b/Sources/Cache/CacheConfig.swift @@ -23,7 +23,7 @@ import Combine import Foundation -class CacheConfig { +struct CacheConfig { let location: CacheLocation? let eventPublisher: EventPublisher diff --git a/Sources/Cache/CacheEvent.swift b/Sources/Cache/CacheEvent.swift index 35edd8c..13e417d 100644 --- a/Sources/Cache/CacheEvent.swift +++ b/Sources/Cache/CacheEvent.swift @@ -23,7 +23,7 @@ import Foundation /// Cache internal events that might be useful for debugging. -public enum CacheEvent { +public enum CacheEvent: Sendable { /// Cache was unable to load from the file. Will happen on first launch or if the Value type changes. case unableToLoad(URL, Error) diff --git a/Sources/Cache/CacheKey.swift b/Sources/Cache/CacheKey.swift index 8254248..b144c97 100644 --- a/Sources/Cache/CacheKey.swift +++ b/Sources/Cache/CacheKey.swift @@ -23,4 +23,4 @@ import Foundation /// The key used to look items up in cache objects. -public typealias CacheKey = Hashable & Codable +public typealias CacheKey = Hashable & Codable & Sendable diff --git a/Sources/Cache/CacheLayer/MemoryCacheLayer.swift b/Sources/Cache/CacheLayer/MemoryCacheLayer.swift index d6bd754..1b287f8 100644 --- a/Sources/Cache/CacheLayer/MemoryCacheLayer.swift +++ b/Sources/Cache/CacheLayer/MemoryCacheLayer.swift @@ -28,7 +28,7 @@ import UIKit #endif /// A fully in-memory based cache with persistence. -final class MemoryCacheLayer: CacheLayer { +final class MemoryCacheLayer: CacheLayer, @unchecked Sendable { var config = CacheConfig() let policies: [CachePolicy] var cache: [Key: Item] = [:] @@ -89,16 +89,16 @@ final class MemoryCacheLayer: CacheLayer { object: nil, queue: .main ) { [weak self] _ in - guard let strongSelf = self else { return } + guard let self else { return } - strongSelf.lock.lock(); defer { strongSelf.lock.unlock() } + lock.lock(); defer { lock.unlock() } // Bail if empty. - guard !strongSelf.cache.isEmpty else { return } + guard !cache.isEmpty else { return } // Apply a policy that will purge half of the current cache. - let purgeAmount = strongSelf.cache.count / 2 - strongSelf.apply([.maxItemCount(purgeAmount)]) + let purgeAmount = cache.count / 2 + apply([.maxItemCount(purgeAmount)]) } #endif } diff --git a/Sources/Cache/CacheLocation.swift b/Sources/Cache/CacheLocation.swift index 065133c..62330f3 100644 --- a/Sources/Cache/CacheLocation.swift +++ b/Sources/Cache/CacheLocation.swift @@ -23,7 +23,7 @@ import Foundation /// Specifies a directory where ``CacheLayer``s are stored. -public struct CacheLocation { +public struct CacheLocation: Sendable { /// Name of this location. public let locationName: String diff --git a/Sources/Cache/CachePolicy.swift b/Sources/Cache/CachePolicy.swift index 83cecdb..8355e50 100644 --- a/Sources/Cache/CachePolicy.swift +++ b/Sources/Cache/CachePolicy.swift @@ -25,7 +25,7 @@ import Foundation /// Policies that may be applied to each cache source. /// Generally, you would create a different and more lenient policy for each level of cache source. /// Specifying no policies results in caches with unbounded growth. -public enum CachePolicy { +public enum CachePolicy: Sendable { /// The maximum number of key/values the source should track. /// When this count is exceeded, the least recently used values will be purged. case maxItemCount(Int) diff --git a/Sources/DemoApp/DemoApp.xcodeproj/project.pbxproj b/Sources/DemoApp/DemoApp.xcodeproj/project.pbxproj index 09f17fe..b2b5abe 100644 --- a/Sources/DemoApp/DemoApp.xcodeproj/project.pbxproj +++ b/Sources/DemoApp/DemoApp.xcodeproj/project.pbxproj @@ -160,7 +160,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1420; - LastUpgradeCheck = 1420; + LastUpgradeCheck = 1630; TargetAttributes = { 6732C75029BBAD7100D13B5C = { CreatedOnToolsVersion = 14.2; @@ -297,6 +297,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -357,6 +358,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -398,7 +400,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.kroger.DemoApp; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -426,7 +428,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.kroger.DemoApp; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -434,7 +436,6 @@ 6732C77929BBAD7200D13B5C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -453,7 +454,6 @@ 6732C77A29BBAD7200D13B5C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; diff --git a/Sources/DemoApp/DemoApp.xcodeproj/xcshareddata/xcschemes/DemoApp.xcscheme b/Sources/DemoApp/DemoApp.xcodeproj/xcshareddata/xcschemes/DemoApp.xcscheme index 63ded93..9a99c3f 100644 --- a/Sources/DemoApp/DemoApp.xcodeproj/xcshareddata/xcschemes/DemoApp.xcscheme +++ b/Sources/DemoApp/DemoApp.xcodeproj/xcshareddata/xcschemes/DemoApp.xcscheme @@ -1,6 +1,6 @@ Void) { + func getInfo(for product: SampleProduct, _ completion: @escaping @Sendable (ProductInfo) -> Void) { let info: ProductInfo switch product { @@ -71,6 +71,7 @@ struct ProductProvider { } // Sample view model that manages the selected product and the fetched details for that product. +@MainActor class SampleModel: ObservableObject { // The currently selected product and it's details. @Published var selectedProduct: SampleProduct = .product3 @@ -101,11 +102,15 @@ class SampleModel: ObservableObject { // Info not in the cache. Fetch the info and update when complete. self.productInfo = nil self.provider.getInfo(for: product) { info in - // Update the cache. - self.cache[product] = info + Task { @MainActor [weak self] in + guard let self else { return } - // Publish the info. - self.productInfo = info + // Update the cache. + self.cache[product] = info + + // Publish the info. + self.productInfo = info + } } } } diff --git a/Tests/CacheTests/CacheLocationTests.swift b/Tests/CacheTests/CacheLocationTests.swift index def61f5..26323c7 100644 --- a/Tests/CacheTests/CacheLocationTests.swift +++ b/Tests/CacheTests/CacheLocationTests.swift @@ -21,7 +21,7 @@ // SOFTWARE. @testable import Cache -import Gauntlet +import GauntletLegacy import XCTest class CacheLocationTests: XCTestCase { diff --git a/Tests/CacheTests/CacheTests.swift b/Tests/CacheTests/CacheTests.swift index dd46744..e73c705 100644 --- a/Tests/CacheTests/CacheTests.swift +++ b/Tests/CacheTests/CacheTests.swift @@ -21,7 +21,7 @@ // SOFTWARE. @testable import Cache -import Gauntlet +import GauntletLegacy import XCTest final class CacheTestCases: XCTestCase { diff --git a/Tests/CacheTests/CodableFileTests.swift b/Tests/CacheTests/CodableFileTests.swift index 708d22d..62af2ac 100644 --- a/Tests/CacheTests/CodableFileTests.swift +++ b/Tests/CacheTests/CodableFileTests.swift @@ -20,7 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import Gauntlet +import GauntletLegacy @testable import Cache import XCTest diff --git a/Tests/CacheTests/MemoryCacheLayerTests.swift b/Tests/CacheTests/MemoryCacheLayerTests.swift index 8d8272c..f04a07d 100644 --- a/Tests/CacheTests/MemoryCacheLayerTests.swift +++ b/Tests/CacheTests/MemoryCacheLayerTests.swift @@ -21,7 +21,7 @@ // SOFTWARE. @testable import Cache -import Gauntlet +import GauntletLegacy import XCTest class MemoryCacheLayerTestCase: XCTestCase { diff --git a/Tests/CacheTests/MockCacheLayer.swift b/Tests/CacheTests/MockCacheLayer.swift index e4532c8..d7632cd 100644 --- a/Tests/CacheTests/MockCacheLayer.swift +++ b/Tests/CacheTests/MockCacheLayer.swift @@ -23,7 +23,7 @@ @testable import Cache import Foundation -extension CacheItem: @retroactive Equatable where Key == String, Value: Equatable { +extension CacheItem: Equatable where Key == String, Value: Equatable { public static func == (lhs: CacheItem, rhs: CacheItem) -> Bool { lhs.key == rhs.key && lhs.creationDate == rhs.creationDate &&