Skip to content

Commit 81ec52b

Browse files
committed
Set SWIFT_STRICT_CONCURRENCY to complete in EssentialFeed and fix all warnings
1 parent e65bd9b commit 81ec52b

File tree

39 files changed

+342
-301
lines changed

39 files changed

+342
-301
lines changed

EssentialApp/EssentialAppTests/CommentsUIIntegrationTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import EssentialApp
99
import EssentialFeed
1010
import EssentialFeediOS
1111

12+
@MainActor
1213
class CommentsUIIntegrationTests: XCTestCase {
1314

1415
func test_commentsView_hasTitle() {

EssentialApp/EssentialAppTests/FeedAcceptanceTests.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import EssentialFeed
77
import EssentialFeediOS
88
@testable import EssentialApp
99

10+
@MainActor
1011
class FeedAcceptanceTests: XCTestCase {
1112

1213
func test_onLaunch_displaysRemoteFeedWhenCustomerHasConnectivity() throws {
@@ -183,6 +184,7 @@ class FeedAcceptanceTests: XCTestCase {
183184

184185
}
185186

187+
@MainActor
186188
extension CoreDataFeedStore {
187189
static var empty: CoreDataFeedStore {
188190
get throws {

EssentialApp/EssentialAppTests/FeedUIIntegrationTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import EssentialApp
88
import EssentialFeed
99
import EssentialFeediOS
1010

11+
@MainActor
1112
class FeedUIIntegrationTests: XCTestCase {
1213

1314
func test_feedView_hasTitle() {

EssentialApp/EssentialAppTests/SceneDelegateTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import XCTest
66
import EssentialFeediOS
77
@testable import EssentialApp
88

9+
@MainActor
910
class SceneDelegateTests: XCTestCase {
1011

1112
func test_configureWindow_setsWindowAsKeyAndVisible() throws {

EssentialFeed/EssentialFeed.xcodeproj/project.pbxproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,7 +1543,9 @@
15431543
SKIP_INSTALL = YES;
15441544
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
15451545
SUPPORTS_MACCATALYST = NO;
1546+
SWIFT_APPROACHABLE_CONCURRENCY = YES;
15461547
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
1548+
SWIFT_STRICT_CONCURRENCY = complete;
15471549
SWIFT_VERSION = 5.0;
15481550
TARGETED_DEVICE_FAMILY = 1;
15491551
};
@@ -1577,6 +1579,8 @@
15771579
SKIP_INSTALL = YES;
15781580
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
15791581
SUPPORTS_MACCATALYST = NO;
1582+
SWIFT_APPROACHABLE_CONCURRENCY = YES;
1583+
SWIFT_STRICT_CONCURRENCY = complete;
15801584
SWIFT_VERSION = 5.0;
15811585
TARGETED_DEVICE_FAMILY = 1;
15821586
};
@@ -1600,7 +1604,9 @@
16001604
PRODUCT_NAME = "$(TARGET_NAME)";
16011605
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
16021606
SUPPORTS_MACCATALYST = NO;
1607+
SWIFT_APPROACHABLE_CONCURRENCY = YES;
16031608
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
1609+
SWIFT_STRICT_CONCURRENCY = complete;
16041610
SWIFT_VERSION = 5.0;
16051611
TARGETED_DEVICE_FAMILY = 1;
16061612
};
@@ -1624,6 +1630,8 @@
16241630
PRODUCT_NAME = "$(TARGET_NAME)";
16251631
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
16261632
SUPPORTS_MACCATALYST = NO;
1633+
SWIFT_APPROACHABLE_CONCURRENCY = YES;
1634+
SWIFT_STRICT_CONCURRENCY = complete;
16271635
SWIFT_VERSION = 5.0;
16281636
TARGETED_DEVICE_FAMILY = 1;
16291637
};
@@ -1646,6 +1654,8 @@
16461654
PRODUCT_NAME = "$(TARGET_NAME)";
16471655
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
16481656
SUPPORTS_MACCATALYST = NO;
1657+
SWIFT_APPROACHABLE_CONCURRENCY = YES;
1658+
SWIFT_STRICT_CONCURRENCY = complete;
16491659
SWIFT_VERSION = 5.0;
16501660
TARGETED_DEVICE_FAMILY = 1;
16511661
};
@@ -1668,6 +1678,8 @@
16681678
PRODUCT_NAME = "$(TARGET_NAME)";
16691679
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
16701680
SUPPORTS_MACCATALYST = NO;
1681+
SWIFT_APPROACHABLE_CONCURRENCY = YES;
1682+
SWIFT_STRICT_CONCURRENCY = complete;
16711683
SWIFT_VERSION = 5.0;
16721684
TARGETED_DEVICE_FAMILY = 1;
16731685
};
@@ -1690,6 +1702,8 @@
16901702
PRODUCT_NAME = "$(TARGET_NAME)";
16911703
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
16921704
SUPPORTS_MACCATALYST = NO;
1705+
SWIFT_APPROACHABLE_CONCURRENCY = YES;
1706+
SWIFT_STRICT_CONCURRENCY = complete;
16931707
SWIFT_VERSION = 5.0;
16941708
TARGETED_DEVICE_FAMILY = 1;
16951709
};
@@ -1712,6 +1726,8 @@
17121726
PRODUCT_NAME = "$(TARGET_NAME)";
17131727
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
17141728
SUPPORTS_MACCATALYST = NO;
1729+
SWIFT_APPROACHABLE_CONCURRENCY = YES;
1730+
SWIFT_STRICT_CONCURRENCY = complete;
17151731
SWIFT_VERSION = 5.0;
17161732
TARGETED_DEVICE_FAMILY = 1;
17171733
};

EssentialFeed/EssentialFeed/Feed Cache/Infrastructure/CoreData/CoreDataFeedStore.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
import CoreData
66

7-
public final class CoreDataFeedStore {
7+
public final class CoreDataFeedStore: Sendable {
88
private static let modelName = "FeedStore"
9+
10+
@MainActor
911
private static let model = NSManagedObjectModel.with(name: modelName, in: Bundle(for: CoreDataFeedStore.self))
1012

1113
private let container: NSPersistentContainer
@@ -25,11 +27,16 @@ public final class CoreDataFeedStore {
2527
context == container.viewContext ? .main : .background
2628
}
2729

28-
public init(storeURL: URL, contextQueue: ContextQueue = .background) throws {
30+
@MainActor
31+
public convenience init(storeURL: URL, contextQueue: ContextQueue = .background) throws {
2932
guard let model = CoreDataFeedStore.model else {
3033
throw StoreError.modelNotFound
3134
}
3235

36+
try self.init(storeURL: storeURL, contextQueue: contextQueue, model: model)
37+
}
38+
39+
public init(storeURL: URL, contextQueue: ContextQueue = .background, model: NSManagedObjectModel) throws {
3340
do {
3441
container = try NSPersistentContainer.load(name: CoreDataFeedStore.modelName, model: model, url: storeURL)
3542
context = contextQueue == .main ? container.viewContext : container.newBackgroundContext()
@@ -38,7 +45,7 @@ public final class CoreDataFeedStore {
3845
}
3946
}
4047

41-
public func perform(_ action: @escaping () -> Void) {
48+
public func perform(_ action: @Sendable @escaping () -> Void) {
4249
context.perform(action)
4350
}
4451

EssentialFeed/EssentialFeed/Shared API Infra/URLSessionHTTPClient.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public final class URLSessionHTTPClient: HTTPClient {
2121
}
2222
}
2323

24-
public func get(from url: URL, completion: @escaping (HTTPClient.Result) -> Void) -> HTTPClientTask {
24+
public func get(from url: URL, completion: @Sendable @escaping (HTTPClient.Result) -> Void) -> HTTPClientTask {
2525
let task = session.dataTask(with: url) { data, response, error in
2626
completion(Result {
2727
if let error = error {

EssentialFeed/EssentialFeed/Shared API/HTTPClient.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ public protocol HTTPClient {
1414
/// The completion handler can be invoked in any thread.
1515
/// Clients are responsible to dispatch to appropriate threads, if needed.
1616
@discardableResult
17-
func get(from url: URL, completion: @escaping (Result) -> Void) -> HTTPClientTask
17+
func get(from url: URL, completion: @Sendable @escaping (Result) -> Void) -> HTTPClientTask
1818
}

EssentialFeed/EssentialFeedAPIEndToEndTests/EssentialFeedAPIEndToEndTests.swift

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
import XCTest
66
import EssentialFeed
77

8+
@MainActor
89
class EssentialFeedAPIEndToEndTests: XCTestCase {
910

10-
func test_endToEndTestServerGETFeedResult_matchesFixedTestAccountData() {
11-
switch getFeedResult() {
11+
func test_endToEndTestServerGETFeedResult_matchesFixedTestAccountData() async {
12+
switch await getFeedResult() {
1213
case let .success(imageFeed)?:
1314
XCTAssertEqual(imageFeed.count, 8, "Expected 8 images in the test account image feed")
1415
XCTAssertEqual(imageFeed[0], expectedImage(at: 0))
@@ -28,8 +29,8 @@ class EssentialFeedAPIEndToEndTests: XCTestCase {
2829
}
2930
}
3031

31-
func test_endToEndTestServerGETFeedImageDataResult_matchesFixedTestAccountData() {
32-
switch getFeedImageDataResult() {
32+
func test_endToEndTestServerGETFeedImageDataResult_matchesFixedTestAccountData() async {
33+
switch await getFeedImageDataResult() {
3334
case let .success(data)?:
3435
XCTAssertFalse(data.isEmpty, "Expected non-empty image data")
3536

@@ -43,45 +44,37 @@ class EssentialFeedAPIEndToEndTests: XCTestCase {
4344

4445
// MARK: - Helpers
4546

46-
private func getFeedResult(file: StaticString = #filePath, line: UInt = #line) -> Swift.Result<[FeedImage], Error>? {
47+
private func getFeedResult(file: StaticString = #filePath, line: UInt = #line) async -> Swift.Result<[FeedImage], Error>? {
4748
let client = ephemeralClient()
48-
let exp = expectation(description: "Wait for load completion")
4949

50-
var receivedResult: Swift.Result<[FeedImage], Error>?
51-
client.get(from: feedTestServerURL) { result in
52-
receivedResult = result.flatMap { (data, response) in
53-
do {
54-
return .success(try FeedItemsMapper.map(data, from: response))
55-
} catch {
56-
return .failure(error)
57-
}
50+
return await withCheckedContinuation { continuation in
51+
client.get(from: feedTestServerURL) { result in
52+
continuation.resume(returning: result.flatMap { (data, response) in
53+
do {
54+
return .success(try FeedItemsMapper.map(data, from: response))
55+
} catch {
56+
return .failure(error)
57+
}
58+
})
5859
}
59-
exp.fulfill()
6060
}
61-
wait(for: [exp], timeout: 5.0)
62-
63-
return receivedResult
6461
}
6562

66-
private func getFeedImageDataResult(file: StaticString = #filePath, line: UInt = #line) -> Result<Data, Error>? {
63+
private func getFeedImageDataResult(file: StaticString = #filePath, line: UInt = #line) async -> Result<Data, Error>? {
6764
let client = ephemeralClient()
6865
let url = feedTestServerURL.appendingPathComponent("73A7F70C-75DA-4C2E-B5A3-EED40DC53AA6/image")
69-
let exp = expectation(description: "Wait for load completion")
7066

71-
var receivedResult: Result<Data, Error>?
72-
client.get(from: url) { result in
73-
receivedResult = result.flatMap { (data, response) in
74-
do {
75-
return .success(try FeedImageDataMapper.map(data, from: response))
76-
} catch {
77-
return .failure(error)
78-
}
67+
return await withCheckedContinuation { continuation in
68+
client.get(from: url) { result in
69+
continuation.resume(returning: result.flatMap { (data, response) in
70+
do {
71+
return .success(try FeedImageDataMapper.map(data, from: response))
72+
} catch {
73+
return .failure(error)
74+
}
75+
})
7976
}
80-
exp.fulfill()
8177
}
82-
wait(for: [exp], timeout: 5.0)
83-
84-
return receivedResult
8578
}
8679

8780
private var feedTestServerURL: URL {

EssentialFeed/EssentialFeedCacheIntegrationTests/EssentialFeedCacheIntegrationTests.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@
55
import XCTest
66
import EssentialFeed
77

8+
@MainActor
89
class EssentialFeedCacheIntegrationTests: XCTestCase {
910

10-
override func setUp() {
11-
super.setUp()
11+
override func setUp() async throws {
12+
try await super.setUp()
1213

1314
setupEmptyStoreState()
1415
}
1516

16-
override func tearDown() {
17-
super.tearDown()
17+
override func tearDown() async throws {
18+
try await super.tearDown()
1819

1920
undoStoreSideEffects()
2021
}

0 commit comments

Comments
 (0)