Skip to content

Commit c1ea63b

Browse files
committed
feat: Support for strict concurrency
1 parent f136bf2 commit c1ea63b

File tree

6 files changed

+45
-21
lines changed

6 files changed

+45
-21
lines changed

Demo Project/ResponsiveTextFieldDemo.xcodeproj/project.pbxproj

+9-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
archiveVersion = 1;
44
classes = {
55
};
6-
objectVersion = 52;
6+
objectVersion = 54;
77
objects = {
88

99
/* Begin PBXBuildFile section */
@@ -108,8 +108,9 @@
108108
A328FAA525FD8A5300B9CE72 /* Project object */ = {
109109
isa = PBXProject;
110110
attributes = {
111+
BuildIndependentTargetsInParallel = YES;
111112
LastSwiftUpdateCheck = 1240;
112-
LastUpgradeCheck = 1240;
113+
LastUpgradeCheck = 1600;
113114
TargetAttributes = {
114115
A328FAAC25FD8A5300B9CE72 = {
115116
CreatedOnToolsVersion = 12.4;
@@ -196,6 +197,7 @@
196197
DEBUG_INFORMATION_FORMAT = dwarf;
197198
ENABLE_STRICT_OBJC_MSGSEND = YES;
198199
ENABLE_TESTABILITY = YES;
200+
ENABLE_USER_SCRIPT_SANDBOXING = YES;
199201
GCC_C_LANGUAGE_STANDARD = gnu11;
200202
GCC_DYNAMIC_NO_PIC = NO;
201203
GCC_NO_COMMON_BLOCKS = YES;
@@ -257,6 +259,7 @@
257259
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
258260
ENABLE_NS_ASSERTIONS = NO;
259261
ENABLE_STRICT_OBJC_MSGSEND = YES;
262+
ENABLE_USER_SCRIPT_SANDBOXING = YES;
260263
GCC_C_LANGUAGE_STANDARD = gnu11;
261264
GCC_NO_COMMON_BLOCKS = YES;
262265
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -291,6 +294,8 @@
291294
);
292295
PRODUCT_BUNDLE_IDENTIFIER = co.uk.lukeredpath.ResponsiveTextField;
293296
PRODUCT_NAME = "$(TARGET_NAME)";
297+
SWIFT_STRICT_CONCURRENCY = complete;
298+
SWIFT_UPCOMING_FEATURE_INFER_SENDABLE_FROM_CAPTURES = YES;
294299
SWIFT_VERSION = 5.0;
295300
TARGETED_DEVICE_FAMILY = "1,2";
296301
};
@@ -312,6 +317,8 @@
312317
);
313318
PRODUCT_BUNDLE_IDENTIFIER = co.uk.lukeredpath.ResponsiveTextField;
314319
PRODUCT_NAME = "$(TARGET_NAME)";
320+
SWIFT_STRICT_CONCURRENCY = complete;
321+
SWIFT_UPCOMING_FEATURE_INFER_SENDABLE_FROM_CAPTURES = YES;
315322
SWIFT_VERSION = 5.0;
316323
TARGETED_DEVICE_FAMILY = "1,2";
317324
};

Package.swift

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.3
1+
// swift-tools-version:5.10
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
@@ -20,10 +20,20 @@ let package = Package(
2020
name: "ResponsiveTextField",
2121
dependencies: [
2222
.product(name: "CombineSchedulers", package: "combine-schedulers")
23-
]),
23+
],
24+
swiftSettings: [
25+
.enableExperimentalFeature("StrictConcurrency"),
26+
.enableUpcomingFeature("InferSendableFromCaptures")
27+
]
28+
),
2429
.testTarget(
2530
name: "ResponsiveTextFieldTests",
2631
dependencies: ["ResponsiveTextField", "SnapshotTesting"],
27-
exclude: ["__Snapshots__"]),
32+
exclude: ["__Snapshots__"],
33+
swiftSettings: [
34+
.enableExperimentalFeature("StrictConcurrency"),
35+
.enableUpcomingFeature("InferSendableFromCaptures")
36+
]
37+
)
2838
]
2939
)

ResponsiveTextField.xcworkspace/xcshareddata/xcschemes/Demo App.xcscheme

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1240"
3+
LastUpgradeVersion = "1600"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"

ResponsiveTextField.xcworkspace/xcshareddata/xcschemes/ResponsiveTextField.xcscheme

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1240"
3+
LastUpgradeVersion = "1600"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"

Sources/ResponsiveTextField/ResponsiveTextField.swift

+15-13
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,14 @@ public struct ResponsiveTextField {
153153

154154
// MARK: - Managing the first responder state
155155

156-
public struct FirstResponderStateChangeHandler {
156+
@MainActor
157+
public struct FirstResponderStateChangeHandler: Sendable {
157158
/// A closure that will be called when the first responder state changes.
158159
///
159160
/// - Parameters:
160161
/// - Bool: A boolean indicating if the text field is now the first responder or not.
161162
///
162-
public var handleStateChange: (Bool) -> Void
163+
public var handleStateChange: @Sendable @MainActor (Bool) -> Void
163164

164165
/// Allows fine-grained control over if the text field should become the first responder.
165166
///
@@ -169,7 +170,7 @@ public struct FirstResponderStateChangeHandler {
169170
/// If the responder change was triggered programatically by a `FirstResponderDemand`
170171
/// and this returns `false` the demand will still be marked as fulfilled and reset to `nil`.
171172
///
172-
public var canBecomeFirstResponder: (() -> Bool)?
173+
public var canBecomeFirstResponder: (@Sendable @MainActor () -> Bool)?
173174

174175
/// Allows fine-grained control over if the text field should resign the first responder.
175176
///
@@ -179,21 +180,21 @@ public struct FirstResponderStateChangeHandler {
179180
/// If the responder change was triggered programatically by a `FirstResponderDemand`
180181
/// and this returns `false` the demand will still be marked as fulfilled and reset to `nil`.
181182
///
182-
public var canResignFirstResponder: (() -> Bool)?
183+
public var canResignFirstResponder: (@Sendable @MainActor () -> Bool)?
183184

184185
/// Initialises a state change handler with a `handleStateChange` callback.
185186
///
186187
/// Most of the time this is the only callback that you will need to provide so this initialiser
187188
/// can be called with trailing closure syntax.
188189
///
189-
public init(handleStateChange: @escaping (Bool) -> Void) {
190+
public init(handleStateChange: @escaping @Sendable @MainActor (Bool) -> Void) {
190191
self.handleStateChange = handleStateChange
191192
}
192193

193194
public init(
194-
handleStateChange: @escaping (Bool) -> Void,
195-
canBecomeFirstResponder: (() -> Bool)? = nil,
196-
canResignFirstResponder: (() -> Bool)? = nil
195+
handleStateChange: @escaping @Sendable @MainActor (Bool) -> Void,
196+
canBecomeFirstResponder: (@Sendable @MainActor () -> Bool)? = nil,
197+
canResignFirstResponder: (@Sendable @MainActor () -> Bool)? = nil
197198
) {
198199
self.handleStateChange = handleStateChange
199200
self.canBecomeFirstResponder = canBecomeFirstResponder
@@ -253,7 +254,8 @@ public struct FirstResponderStateChangeHandler {
253254
/// cycle completes using this method. You can pass in any suitable scheduler, such as `RunLoop.main` or
254255
/// `DispatchQueue.main`.
255256
///
256-
public func receive<S: Scheduler>(on scheduler: S, options: S.SchedulerOptions? = nil) -> Self {
257+
public func receive<S: Scheduler>(on scheduler: S, options: S.SchedulerOptions? = nil) -> Self
258+
where S: Sendable, S.SchedulerOptions: Sendable {
257259
return .init(
258260
handleStateChange: { isFirstResponder in
259261
scheduler.schedule(options: options) {
@@ -288,7 +290,7 @@ extension FirstResponderStateChangeHandler {
288290

289291
/// Represents a request to change the text field's first responder state.
290292
///
291-
public enum FirstResponderDemand: Equatable {
293+
public enum FirstResponderDemand: Equatable, Sendable {
292294
/// The text field should become first responder on the next view update.
293295
case shouldBecomeFirstResponder
294296

@@ -466,10 +468,10 @@ extension ResponsiveTextField {
466468
/// that you use in your app. Configurations are composable and can be combined to create more
467469
/// detailed configurations.
468470
///
469-
public struct Configuration {
470-
var configure: (UITextField) -> Void
471+
public struct Configuration: Sendable {
472+
var configure: @MainActor @Sendable (UITextField) -> Void
471473

472-
public init(configure: @escaping (UITextField) -> Void) {
474+
public init(configure: @escaping @MainActor @Sendable (UITextField) -> Void) {
473475
self.configure = configure
474476
}
475477

Tests/ResponsiveTextFieldTests/ResponsiveTextFieldTests.swift

+6-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ final class ResponsiveTextFieldTests: XCTestCase {
1616
}
1717
}
1818

19+
@MainActor
1920
func testEmptyTextField() {
2021
assertSnapshot(
2122
of: ResponsiveTextField(
@@ -29,6 +30,7 @@ final class ResponsiveTextFieldTests: XCTestCase {
2930
)
3031
}
3132

33+
@MainActor
3234
func testTextFieldWithText() {
3335
assertSnapshot(
3436
of: ResponsiveTextField(
@@ -42,6 +44,7 @@ final class ResponsiveTextFieldTests: XCTestCase {
4244
)
4345
}
4446

47+
@MainActor
4548
func testSecureTextEntry() {
4649
assertSnapshot(
4750
of: ResponsiveTextField(
@@ -55,6 +58,7 @@ final class ResponsiveTextFieldTests: XCTestCase {
5558
)
5659
}
5760

61+
@MainActor
5862
func testTextFieldCustomTextStyle() {
5963
assertSnapshot(
6064
of: ResponsiveTextField(
@@ -71,7 +75,8 @@ final class ResponsiveTextFieldTests: XCTestCase {
7175
)
7276
}
7377

74-
func testTextFieldCustomTextAlignment() {
78+
@MainActor
79+
func testTextFieldCustomTextAlignment() {
7580
assertSnapshot(
7681
of: ResponsiveTextField(
7782
placeholder: "Placeholder Text",

0 commit comments

Comments
 (0)