Skip to content

Commit d27c189

Browse files
authored
Migrate to swift6 (#25)
* Remove global variables * Add sendable * Enable swift6 mode * Remove minimum version * Drop Xcode15.4 * Add verbose option * Update support version * Remove verbose option
1 parent a304b99 commit d27c189

File tree

9 files changed

+47
-41
lines changed

9 files changed

+47
-41
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,8 @@ jobs:
1818
DEVELOPER_DIR: '/Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer'
1919
strategy:
2020
matrix:
21-
xcode: [ 15.4, 16.4 ]
21+
xcode: [ 16.4 ]
2222
include:
23-
- xcode: 15.4
24-
macos: macos-14
2523
- xcode: 16.4
2624
macos: macos-15
2725
steps:
@@ -37,11 +35,8 @@ jobs:
3735
DEVELOPER_DIR: '/Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer'
3836
strategy:
3937
matrix:
40-
xcode: [ 15.4, 16.4 ]
38+
xcode: [ 16.4 ]
4139
include:
42-
- xcode: 15.4
43-
macos: macos-14
44-
destination: "platform=iOS Simulator,name=iPhone 15,OS=17.5"
4540
- xcode: 16.4
4641
macos: macos-15
4742
destination: "platform=iOS Simulator,name=iPhone 16,OS=18.5"
@@ -56,11 +51,8 @@ jobs:
5651
runs-on: ${{ matrix.macos }}
5752
strategy:
5853
matrix:
59-
xcode: [ 15.4, 16.4 ]
54+
xcode: [ 16.4 ]
6055
include:
61-
- xcode: 15.4
62-
macos: macos-14
63-
destination: "platform=tvOS Simulator,name=Apple TV,OS=17.5"
6456
- xcode: 16.4
6557
macos: macos-15
6658
destination: "platform=tvOS Simulator,name=Apple TV,OS=18.5"
@@ -77,11 +69,8 @@ jobs:
7769
runs-on: ${{ matrix.macos }}
7870
strategy:
7971
matrix:
80-
xcode: [ 15.4, 16.4 ]
72+
xcode: [ 16.4 ]
8173
include:
82-
- xcode: 15.4
83-
macos: macos-14
84-
destination: "platform=watchOS Simulator,name=Apple Watch Series 9 (41mm),OS=10.5"
8574
- xcode: 16.4
8675
macos: macos-15
8776
destination: "platform=watchOS Simulator,name=Apple Watch Series 10 (42mm),OS=11.5"
@@ -107,6 +96,8 @@ jobs:
10796
cocoapods:
10897
name: CocoaPods
10998
runs-on: macos-15
99+
env:
100+
DEVELOPER_DIR: '/Applications/Xcode_16.4.app/Contents/Developer'
110101
steps:
111102
- name: Checkout Repo
112103
uses: actions/checkout@v4

Example/Example.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@
285285
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
286286
GCC_WARN_UNUSED_FUNCTION = YES;
287287
GCC_WARN_UNUSED_VARIABLE = YES;
288-
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
288+
IPHONEOS_DEPLOYMENT_TARGET = 15;
289289
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
290290
MTL_FAST_MATH = YES;
291291
ONLY_ACTIVE_ARCH = YES;
@@ -340,7 +340,7 @@
340340
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
341341
GCC_WARN_UNUSED_FUNCTION = YES;
342342
GCC_WARN_UNUSED_VARIABLE = YES;
343-
IPHONEOS_DEPLOYMENT_TARGET = 14.5;
343+
IPHONEOS_DEPLOYMENT_TARGET = 15;
344344
MTL_ENABLE_DEBUG_INFO = NO;
345345
MTL_FAST_MATH = YES;
346346
SDKROOT = iphoneos;
@@ -359,7 +359,7 @@
359359
DEVELOPMENT_ASSET_PATHS = "";
360360
ENABLE_PREVIEWS = YES;
361361
INFOPLIST_FILE = Example/Info.plist;
362-
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
362+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
363363
LD_RUNPATH_SEARCH_PATHS = (
364364
"$(inherited)",
365365
"@executable_path/Frameworks",
@@ -380,7 +380,7 @@
380380
DEVELOPMENT_ASSET_PATHS = "";
381381
ENABLE_PREVIEWS = YES;
382382
INFOPLIST_FILE = Example/Info.plist;
383-
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
383+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
384384
LD_RUNPATH_SEARCH_PATHS = (
385385
"$(inherited)",
386386
"@executable_path/Frameworks",

Example/ExampleKit/Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
// swift-tools-version:5.3
1+
// swift-tools-version:6.0
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
55

66
let package = Package(
77
name: "ExampleKit",
88
platforms: [
9-
.iOS(.v14)
9+
.iOS(.v15)
1010
],
1111
products: [
1212
.library(name: "ExampleKit", targets: ["ExampleKit"])

Package.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
// swift-tools-version:5.3
1+
// swift-tools-version:6.0
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
55

66
let package = Package(
77
name: "swift-user-defaults",
88
platforms: [
9-
.macOS(.v10_13),
10-
.iOS(.v12),
9+
.macOS(.v15),
10+
.iOS(.v15),
1111
.watchOS(.v7),
12-
.tvOS(.v12)
12+
.tvOS(.v15)
1313
],
1414
products: [
1515
.library(name: "SwiftUserDefaults", targets: ["SwiftUserDefaults"]),

Sources/SwiftUserDefaults/UserDefaults+Key.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public extension UserDefaults {
6565
///
6666
/// let rawValue = UserDefaults.standard.string(forKey: UserDefaults.Key.userState.rawValue)
6767
/// ```
68-
struct Key: RawRepresentable, Hashable {
68+
struct Key: RawRepresentable, Hashable, Sendable {
6969
/// The underlying string value that is used for assigning a value against within the user defaults.
7070
public let rawValue: String
7171

Sources/SwiftUserDefaults/UserDefaults+Observation.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222

2323
import Foundation
2424

25-
private var userDefaultsObserverContext = 0
26-
2725
public extension UserDefaults {
2826
/// Observes changes to the object associated with the specified key.
2927
///
@@ -59,6 +57,7 @@ public extension UserDefaults {
5957
let userDefaults: UserDefaults
6058
let keyPath: String
6159
let handler: (Change<Any?>) -> Void
60+
private var userDefaultsObserverContext = 0
6261

6362
private(set) var isRegistered: Bool = false
6463

Tests/SwiftUserDefaultsTests/UserDefaultTests.swift

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,31 +85,28 @@ final class UserDefaultTests: XCTestCase {
8585
XCTAssertNil(userDefaults.object(forKey: "BoolKey"))
8686
}
8787

88-
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
8988
func testObserver() {
9089
let wrapper = UserDefault<String>(.init("StringKey"), store: userDefaults, defaultValue: "")
9190

9291
var changes: [UserDefaults.Change<String>] = []
9392
let observer = wrapper.addObserver { changes.append($0) }
94-
addTeardownBlock(observer.invalidate)
9593

9694
wrapper.wrappedValue = "One"
9795
wrapper.reset()
9896
wrapper.wrappedValue = "Two"
9997
userDefaults.x.set("Three", forKey: .init("StringKey"))
10098

10199
XCTAssertEqual(changes, [.initial(""), .update("One"), .update(""), .update("Two"), .update("Three")])
100+
observer.invalidate()
102101
}
103102

104-
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
105103
func testCodableWithDefault() {
106104
let key = UserDefaults.Key("CodableKey")
107105
let wrapper = UserDefault<Subject>(key, strategy: .json, store: userDefaults, defaultValue: Subject(value: "default"))
108106

109107
// Observe changes
110108
var changes: [Subject] = []
111109
let token = wrapper.addObserver(handler: { changes.append($0.value) })
112-
addTeardownBlock(token.invalidate)
113110

114111
// Uses default
115112
XCTAssertNil(userDefaults.object(forKey: key.rawValue))
@@ -135,17 +132,16 @@ final class UserDefaultTests: XCTestCase {
135132
"default",
136133
"default"
137134
])
135+
token.invalidate()
138136
}
139137

140-
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
141138
func testCodable() {
142139
let key = UserDefaults.Key("CodableKey")
143140
let wrapper = UserDefault<Subject?>(key, strategy: .json, store: userDefaults)
144141

145142
// Observe changes
146143
var changes: [Subject?] = []
147144
let token = wrapper.addObserver(handler: { changes.append($0.value) })
148-
addTeardownBlock(token.invalidate)
149145

150146
// nil when unset
151147
XCTAssertNil(userDefaults.object(forKey: key.rawValue))
@@ -178,17 +174,16 @@ final class UserDefaultTests: XCTestCase {
178174
"value",
179175
nil
180176
])
177+
token.invalidate()
181178
}
182179

183-
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
184180
func testRawRepresentableWithDefault() {
185181
let key = UserDefaults.Key("RawRepresentableKey")
186182
let wrapper = UserDefault<RawSubject>(key, store: userDefaults, defaultValue: .foo)
187183

188184
// Observe changes
189185
var changes: [RawSubject] = []
190186
let token = wrapper.addObserver(handler: { changes.append($0.value) })
191-
addTeardownBlock(token.invalidate)
192187

193188
// Uses default
194189
XCTAssertNil(userDefaults.object(forKey: key.rawValue))
@@ -214,17 +209,16 @@ final class UserDefaultTests: XCTestCase {
214209
.foo,
215210
.foo
216211
])
212+
token.invalidate()
217213
}
218214

219-
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
220215
func testRawRepresentable() {
221216
let key = UserDefaults.Key("RawRepresentableKey")
222217
let wrapper = UserDefault<RawSubject?>(key, store: userDefaults)
223218

224219
// Observe changes
225220
var changes: [RawSubject?] = []
226221
let token = wrapper.addObserver(handler: { changes.append($0.value) })
227-
addTeardownBlock(token.invalidate)
228222

229223
// Uses default
230224
XCTAssertNil(userDefaults.object(forKey: key.rawValue))
@@ -256,5 +250,6 @@ final class UserDefaultTests: XCTestCase {
256250
nil,
257251
.baz
258252
])
253+
token.invalidate()
259254
}
260255
}

Tests/SwiftUserDefaultsTests/UserDefaultsObservationTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,27 @@ final class UserDefaultsObservationTests: XCTestCase {
5454
XCTAssertEqual(changes.map(\.value) as NSArray, [nil, "Test", nil, "Default", 1] as NSArray)
5555
XCTAssertEqual(changes.map(\.label), [.initial, .update, .update, .update, .update])
5656
}
57+
58+
func testInvalidateOnDeinit() {
59+
// Given an observer is registered
60+
var changes: [UserDefaults.Change<Any?>] = []
61+
62+
var observer: UserDefaults.Observation? = userDefaults.observeObject(forKey: "TestKey") { change in
63+
changes.append(change)
64+
}
65+
_ = observer
66+
67+
userDefaults.set("Test", forKey: "TestKey")
68+
69+
// When the observer is deallocated
70+
observer = nil
71+
72+
// Then no further changes should be recorded
73+
userDefaults.set("NewTest", forKey: "TestKey")
74+
75+
XCTAssertEqual(changes.map(\.value) as NSArray, [nil, "Test"] as NSArray)
76+
XCTAssertEqual(changes.map(\.label), [.initial, .update])
77+
}
5778
}
5879

5980
private extension UserDefaults.Change {

swift-user-defaults.podspec

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ Pod::Spec.new do |s|
99
s.source = { :git => "https://github.com/cookpad/swift-user-defaults.git", :tag => "#{s.version}" }
1010
s.source_files = "Sources/**/*.{swift}"
1111
s.resource_bundles = {'SwiftUserDefaults' => ['Sources/SwiftUserDefaults/PrivacyInfo.xcprivacy']}
12-
s.swift_version = "5.3"
12+
s.swift_version = "6.0"
1313

14-
s.ios.deployment_target = '12.0'
15-
s.osx.deployment_target = '10.13'
14+
s.ios.deployment_target = '15.0'
15+
s.osx.deployment_target = '15.0'
1616

1717
# Run Unit Tests
1818
s.test_spec 'Tests' do |test_spec|

0 commit comments

Comments
 (0)