From efdd8df82458df247eccd36e69935cfd06ef3273 Mon Sep 17 00:00:00 2001 From: Amy Oulton <62073522+amyoulton@users.noreply.github.com> Date: Mon, 6 Feb 2023 11:46:58 -0800 Subject: [PATCH] Add Sendable conformance (#116) * added Sendable conformance * added LossyArray sendable conformance * updated request failure delegate * fixed concurrency warnings * small conformance additions * finished conformance via the main actor additions * returned removed Sendable in closure * removed un-needed isolation flag * self warnings solved * updated based on convo with nigel --------- Co-authored-by: Amy --- Netable/Example/Models/User.swift | 2 +- .../Example/Services/AuthNetworkService.swift | 6 +- Netable/Example/Services/ErrorService.swift | 14 +- .../Services/GraphQLNetworkService.swift | 2 +- Netable/Example/Services/NetworkService.swift | 12 +- Netable/Example/ViewModels/GraphQLVM.swift | 1 + Netable/Example/ViewModels/HomeVM.swift | 1 + Netable/Example/ViewModels/LoginVM.swift | 1 + Netable/Example/ViewModels/ObservableVM.swift | 1 + Netable/Example/ViewModels/RootVM.swift | 4 +- Netable/Netable.xcodeproj/project.pbxproj | 145 +----------------- ...tableExample.xcscheme => Example.xcscheme} | 20 +-- .../xcshareddata/xcschemes/Netable.xcscheme | 2 +- Netable/Netable/GraphQLRequest.swift | 2 +- Netable/Netable/LossyArray.swift | 2 +- Netable/Netable/Netable.swift | 11 +- Netable/Netable/Request.swift | 10 +- Netable/Netable/SmartUnwrap.swift | 2 +- 18 files changed, 54 insertions(+), 184 deletions(-) rename Netable/Netable.xcodeproj/xcshareddata/xcschemes/{NetableExample.xcscheme => Example.xcscheme} (82%) diff --git a/Netable/Example/Models/User.swift b/Netable/Example/Models/User.swift index f6fbcc0..1144471 100644 --- a/Netable/Example/Models/User.swift +++ b/Netable/Example/Models/User.swift @@ -9,7 +9,7 @@ import Foundation import Netable -struct User: Decodable { +struct User: Decodable, Sendable { let firstName: String let lastName: String let location: String diff --git a/Netable/Example/Services/AuthNetworkService.swift b/Netable/Example/Services/AuthNetworkService.swift index 74716ee..1493f56 100644 --- a/Netable/Example/Services/AuthNetworkService.swift +++ b/Netable/Example/Services/AuthNetworkService.swift @@ -11,7 +11,7 @@ import Foundation import Netable class AuthNetworkService { - static var shared = AuthNetworkService() + static let shared = AuthNetworkService() private let unauthNetable: Netable @@ -65,13 +65,13 @@ class AuthNetworkService { try await netable.request(GetPostsRequest()) } - func createPost(title: String, content: String) { + @MainActor func createPost(title: String, content: String) { // this request is deliberately failing. Since there is a retry configuration set to the authNetable request, // we are going to make use of `cancel()` to cancel the task after sending it so it doesn't try again. let createRequest = Task { do { - let result = try await netable.request(CreatePostRequest(parameters: CreatePostParameters(title: title, content: content))) + try await netable.request(CreatePostRequest(parameters: CreatePostParameters(title: title, content: content))) } catch { print("Create request error: \(error)") } diff --git a/Netable/Example/Services/ErrorService.swift b/Netable/Example/Services/ErrorService.swift index 0eac6ea..2ea9291 100644 --- a/Netable/Example/Services/ErrorService.swift +++ b/Netable/Example/Services/ErrorService.swift @@ -10,17 +10,21 @@ import Combine import Foundation import Netable -class ErrorService { - static var shared = ErrorService() +@MainActor +final class ErrorService { + static let shared = ErrorService() - var errors = PassthroughSubject() + let errors = PassthroughSubject() } + extension ErrorService: RequestFailureDelegate { - func requestDidFail(_ request: T, error: NetableError) { + nonisolated func requestDidFail(_ request: T, error: NetableError) { if case let NetableError.httpError(statusCode, _) = error, statusCode == 401 { return } - errors.send(error) + Task { @MainActor in + errors.send(error) + } } } diff --git a/Netable/Example/Services/GraphQLNetworkService.swift b/Netable/Example/Services/GraphQLNetworkService.swift index 0ca2912..1074017 100644 --- a/Netable/Example/Services/GraphQLNetworkService.swift +++ b/Netable/Example/Services/GraphQLNetworkService.swift @@ -10,7 +10,7 @@ import Foundation import Netable class GraphQLNetworkService { - static var shared = GraphQLNetworkService() + static let shared = GraphQLNetworkService() private let netable = Netable(baseURL: URL(string: "http://localhost:8080/graphql")!) diff --git a/Netable/Example/Services/NetworkService.swift b/Netable/Example/Services/NetworkService.swift index 2b4669c..7688379 100644 --- a/Netable/Example/Services/NetworkService.swift +++ b/Netable/Example/Services/NetworkService.swift @@ -11,17 +11,11 @@ import Foundation import Netable class SimpleNetworkService { - static var shared = SimpleNetworkService() + static let shared = SimpleNetworkService() private let netable = Netable(baseURL: URL(string: "http://localhost:8080/")!) - func getVersion() { - Task { - do { - let version = try await netable.request(GetVersionRequest()) - } catch { - print(error) - } - } + func getVersion() async throws { + try await netable.request(GetVersionRequest()) } } diff --git a/Netable/Example/ViewModels/GraphQLVM.swift b/Netable/Example/ViewModels/GraphQLVM.swift index 836fa1c..ee99090 100644 --- a/Netable/Example/ViewModels/GraphQLVM.swift +++ b/Netable/Example/ViewModels/GraphQLVM.swift @@ -8,6 +8,7 @@ import Foundation +@MainActor class GraphQLVM: ObservableObject { @Published var posts: [Post]? @Published var title: String = "" diff --git a/Netable/Example/ViewModels/HomeVM.swift b/Netable/Example/ViewModels/HomeVM.swift index f34f332..bfd86d5 100644 --- a/Netable/Example/ViewModels/HomeVM.swift +++ b/Netable/Example/ViewModels/HomeVM.swift @@ -9,6 +9,7 @@ import Foundation import Netable +@MainActor class HomeVM: ObservableVM { @Published var title: String = "" @Published var content: String = "" diff --git a/Netable/Example/ViewModels/LoginVM.swift b/Netable/Example/ViewModels/LoginVM.swift index 34e76c0..f40e2a2 100644 --- a/Netable/Example/ViewModels/LoginVM.swift +++ b/Netable/Example/ViewModels/LoginVM.swift @@ -9,6 +9,7 @@ import Combine import Foundation +@MainActor class LoginVM: ObservableVM { @Published var user: User? @Published var username: String = "" diff --git a/Netable/Example/ViewModels/ObservableVM.swift b/Netable/Example/ViewModels/ObservableVM.swift index f9b175f..11f44af 100644 --- a/Netable/Example/ViewModels/ObservableVM.swift +++ b/Netable/Example/ViewModels/ObservableVM.swift @@ -10,6 +10,7 @@ import Combine import Foundation import Netable +@MainActor class ObservableVM: ObservableObject { var cancellables: [AnyCancellable] = [] diff --git a/Netable/Example/ViewModels/RootVM.swift b/Netable/Example/ViewModels/RootVM.swift index 0746847..560e801 100644 --- a/Netable/Example/ViewModels/RootVM.swift +++ b/Netable/Example/ViewModels/RootVM.swift @@ -44,7 +44,9 @@ class RootVM: ObservableVM { } func getVersion() { - SimpleNetworkService.shared.getVersion() + Task { + try await SimpleNetworkService.shared.getVersion() + } } func clearError() { diff --git a/Netable/Netable.xcodeproj/project.pbxproj b/Netable/Netable.xcodeproj/project.pbxproj index 138b84f..91deae1 100644 --- a/Netable/Netable.xcodeproj/project.pbxproj +++ b/Netable/Netable.xcodeproj/project.pbxproj @@ -9,8 +9,6 @@ /* Begin PBXBuildFile section */ 3B00B3C726D7EA3C00A1DF79 /* DecodingError+Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B00B3C626D7EA3C00A1DF79 /* DecodingError+Logging.swift */; }; A63ABCCA24ABB402004DE84E /* RetryConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A63ABCC924ABB402004DE84E /* RetryConfiguration.swift */; }; - B8A18C0D23F2201000941EA6 /* Netable.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B8C9288023E9F68000DB2B37 /* Netable.framework */; }; - B8A18C0E23F2201000941EA6 /* Netable.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B8C9288023E9F68000DB2B37 /* Netable.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; B8C9288A23E9F68000DB2B37 /* Netable.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B8C9288023E9F68000DB2B37 /* Netable.framework */; }; B8C9288F23E9F68000DB2B37 /* NetableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8C9288E23E9F68000DB2B37 /* NetableTests.swift */; }; B8C9289123E9F68000DB2B37 /* Netable.h in Headers */ = {isa = PBXBuildFile; fileRef = B8C9288323E9F68000DB2B37 /* Netable.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -29,7 +27,6 @@ C64ADA47293F9ED900695444 /* ArrayDecodeStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C64ADA46293F9ED900695444 /* ArrayDecodeStrategy.swift */; }; C64F8592241FE4870028E0E9 /* CHANGELOG.md in Resources */ = {isa = PBXBuildFile; fileRef = C64F8591241FE4870028E0E9 /* CHANGELOG.md */; }; C65289F526D01829009D486B /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = C65289F426D01829009D486B /* Config.swift */; }; - C692788626F1254800917E65 /* Swifter in Frameworks */ = {isa = PBXBuildFile; productRef = C692788526F1254800917E65 /* Swifter */; }; C6953F42241A95830044D278 /* LogDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6953F41241A95830044D278 /* LogDestination.swift */; }; C6DA3354293822230076F693 /* LossyArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6DA3353293822230076F693 /* LossyArray.swift */; }; C6F4CFB026D582E8004E6BB8 /* RequestFailedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F4CFAF26D582E8004E6BB8 /* RequestFailedDelegate.swift */; }; @@ -83,13 +80,6 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - B8A18C0F23F2201000941EA6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B8C9287723E9F68000DB2B37 /* Project object */; - proxyType = 1; - remoteGlobalIDString = B8C9287F23E9F68000DB2B37; - remoteInfo = Netable; - }; B8C9288B23E9F68000DB2B37 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = B8C9287723E9F68000DB2B37 /* Project object */; @@ -107,17 +97,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - B8A18C1123F2201000941EA6 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - B8A18C0E23F2201000941EA6 /* Netable.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; E186202029425EE7009B6E0C /* Embeded Framworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -134,7 +113,6 @@ /* Begin PBXFileReference section */ 3B00B3C626D7EA3C00A1DF79 /* DecodingError+Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DecodingError+Logging.swift"; sourceTree = ""; }; A63ABCC924ABB402004DE84E /* RetryConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RetryConfiguration.swift; sourceTree = ""; }; - B822C8EB23F20E8900D7BDAD /* NetableExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NetableExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; B8C9288023E9F68000DB2B37 /* Netable.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Netable.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B8C9288323E9F68000DB2B37 /* Netable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Netable.h; sourceTree = ""; }; B8C9288423E9F68000DB2B37 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -207,15 +185,6 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - B822C8E823F20E8900D7BDAD /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - B8A18C0D23F2201000941EA6 /* Netable.framework in Frameworks */, - C692788626F1254800917E65 /* Swifter in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; B8C9287D23E9F68000DB2B37 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -259,7 +228,6 @@ children = ( B8C9288023E9F68000DB2B37 /* Netable.framework */, B8C9288923E9F68000DB2B37 /* NetableTests.xctest */, - B822C8EB23F20E8900D7BDAD /* NetableExample.app */, E1275822292E9C5A0047E5DD /* Example.app */, ); name = Products; @@ -455,28 +423,6 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - B822C8EA23F20E8900D7BDAD /* NetableExample */ = { - isa = PBXNativeTarget; - buildConfigurationList = B822C8FE23F20E8B00D7BDAD /* Build configuration list for PBXNativeTarget "NetableExample" */; - buildPhases = ( - B822C8E723F20E8900D7BDAD /* Sources */, - B822C8E823F20E8900D7BDAD /* Frameworks */, - B822C8E923F20E8900D7BDAD /* Resources */, - B8A18C1123F2201000941EA6 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - B8A18C1023F2201000941EA6 /* PBXTargetDependency */, - ); - name = NetableExample; - packageProductDependencies = ( - C692788526F1254800917E65 /* Swifter */, - ); - productName = NetableExample; - productReference = B822C8EB23F20E8900D7BDAD /* NetableExample.app */; - productType = "com.apple.product-type.application"; - }; B8C9287F23E9F68000DB2B37 /* Netable */ = { isa = PBXNativeTarget; buildConfigurationList = B8C9289423E9F68000DB2B37 /* Build configuration list for PBXNativeTarget "Netable" */; @@ -544,12 +490,9 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1410; - LastUpgradeCheck = 1130; + LastUpgradeCheck = 1410; ORGANIZATIONNAME = "Steamclock Software"; TargetAttributes = { - B822C8EA23F20E8900D7BDAD = { - CreatedOnToolsVersion = 11.3.1; - }; B8C9287F23E9F68000DB2B37 = { CreatedOnToolsVersion = 11.3.1; LastSwiftMigration = 1130; @@ -580,20 +523,12 @@ targets = ( B8C9287F23E9F68000DB2B37 /* Netable */, B8C9288823E9F68000DB2B37 /* NetableTests */, - B822C8EA23F20E8900D7BDAD /* NetableExample */, E1275821292E9C5A0047E5DD /* Example */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - B822C8E923F20E8900D7BDAD /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; B8C9287E23E9F68000DB2B37 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -629,13 +564,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - B822C8E723F20E8900D7BDAD /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; B8C9287C23E9F68000DB2B37 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -714,11 +642,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - B8A18C1023F2201000941EA6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = B8C9287F23E9F68000DB2B37 /* Netable */; - targetProxy = B8A18C0F23F2201000941EA6 /* PBXContainerItemProxy */; - }; B8C9288C23E9F68000DB2B37 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = B8C9287F23E9F68000DB2B37 /* Netable */; @@ -732,52 +655,6 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - B822C8FC23F20E8B00D7BDAD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = NetableExample/Resources/NetableExample.entitlements; - CODE_SIGN_STYLE = Automatic; - DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; - DEVELOPMENT_TEAM = GH868RP95T; - INFOPLIST_FILE = NetableExample/Resources/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.steamclock.NetableExample; - PRODUCT_NAME = NetableExample; - SUPPORTS_MACCATALYST = YES; - SWIFT_STRICT_CONCURRENCY = complete; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - B822C8FD23F20E8B00D7BDAD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = NetableExample/Resources/NetableExample.entitlements; - CODE_SIGN_STYLE = Automatic; - DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; - DEVELOPMENT_TEAM = GH868RP95T; - INFOPLIST_FILE = NetableExample/Resources/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.steamclock.NetableExample; - PRODUCT_NAME = NetableExample; - SUPPORTS_MACCATALYST = YES; - SWIFT_STRICT_CONCURRENCY = complete; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; B8C9289223E9F68000DB2B37 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -804,6 +681,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -868,6 +746,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -925,7 +804,7 @@ SKIP_INSTALL = YES; SUPPORTS_MACCATALYST = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_STRICT_CONCURRENCY = minimal; + SWIFT_STRICT_CONCURRENCY = complete; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -955,7 +834,7 @@ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; SUPPORTS_MACCATALYST = YES; - SWIFT_STRICT_CONCURRENCY = minimal; + SWIFT_STRICT_CONCURRENCY = complete; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -1064,15 +943,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - B822C8FE23F20E8B00D7BDAD /* Build configuration list for PBXNativeTarget "NetableExample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - B822C8FC23F20E8B00D7BDAD /* Debug */, - B822C8FD23F20E8B00D7BDAD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; B8C9287A23E9F68000DB2B37 /* Build configuration list for PBXProject "Netable" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -1123,11 +993,6 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - C692788526F1254800917E65 /* Swifter */ = { - isa = XCSwiftPackageProductDependency; - package = C692788426F1254800917E65 /* XCRemoteSwiftPackageReference "swifter" */; - productName = Swifter; - }; E1275845292EDD110047E5DD /* Swifter */ = { isa = XCSwiftPackageProductDependency; package = C692788426F1254800917E65 /* XCRemoteSwiftPackageReference "swifter" */; diff --git a/Netable/Netable.xcodeproj/xcshareddata/xcschemes/NetableExample.xcscheme b/Netable/Netable.xcodeproj/xcshareddata/xcschemes/Example.xcscheme similarity index 82% rename from Netable/Netable.xcodeproj/xcshareddata/xcschemes/NetableExample.xcscheme rename to Netable/Netable.xcodeproj/xcshareddata/xcschemes/Example.xcscheme index 6bdbe8b..927d441 100644 --- a/Netable/Netable.xcodeproj/xcshareddata/xcschemes/NetableExample.xcscheme +++ b/Netable/Netable.xcodeproj/xcshareddata/xcschemes/Example.xcscheme @@ -1,6 +1,6 @@ @@ -44,9 +44,9 @@ runnableDebuggingMode = "0"> @@ -61,9 +61,9 @@ runnableDebuggingMode = "0"> diff --git a/Netable/Netable.xcodeproj/xcshareddata/xcschemes/Netable.xcscheme b/Netable/Netable.xcodeproj/xcshareddata/xcschemes/Netable.xcscheme index c923214..f88b248 100644 --- a/Netable/Netable.xcodeproj/xcshareddata/xcschemes/Netable.xcscheme +++ b/Netable/Netable.xcodeproj/xcshareddata/xcschemes/Netable.xcscheme @@ -1,6 +1,6 @@ { +public struct LossyArray: Sendable where Element: Sendable { /// All elements of the array that decoded successfully. public var elements: [Element] diff --git a/Netable/Netable/Netable.swift b/Netable/Netable/Netable.swift index f5587f1..0d33fc9 100644 --- a/Netable/Netable/Netable.swift +++ b/Netable/Netable/Netable.swift @@ -154,19 +154,16 @@ public actor Netable { * * - returns: A tuple that contains a reference to the `Task`, for cancellation, and a PassthroughSubject to monitor for results. */ + public nonisolated func request(_ request: T) -> (task: Task<(), Never>, subject: Publishers.ReceiveOn, Never>, RunLoop>) { - let resultSubject = PassthroughSubject, Never>() + let resultSubject = PassthroughSubject, Never>() let task = Task { do { let finalResource = try await self.request(request) - await MainActor.run { resultSubject.send(.success(finalResource)) - } } catch { - await MainActor.run { resultSubject.send(.failure(error.netableError)) - } } } @@ -269,9 +266,11 @@ public actor Netable { } internal func sendToErrorDelegates(_ error: NetableError, request: T) { - Task { @MainActor in + Task { self.requestFailureSubject.send(error) self.requestFailureDelegate?.requestDidFail(request, error: error) } } } + +extension AnyPublisher: @unchecked Sendable {} diff --git a/Netable/Netable/Request.swift b/Netable/Netable/Request.swift index d96ce54..fafddec 100644 --- a/Netable/Netable/Request.swift +++ b/Netable/Netable/Request.swift @@ -22,7 +22,7 @@ public protocol Request: Sendable { /// An optional convenience type that Netable will try to use to decode your response if `RawResource` fails for any reason. /// See `FallbackDecoderViewController` for an example. - associatedtype FallbackResource: Sendable = AnyObject + associatedtype FallbackResource: Sendable = Sendable /// Allows for top-level arrays to be partially decoded if some elements fail to decode. var arrayDecodeStrategy: ArrayDecodeStrategy { get } @@ -124,7 +124,8 @@ public extension Request where FinalResource == RawResource { public extension Request where RawResource: Sequence, RawResource: Decodable, - RawResource.Element: Decodable + RawResource.Element: Decodable, + RawResource.Element: Sendable { func decode(_ data: Data?, defaultDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> RawResource { let decoder = JSONDecoder() @@ -185,7 +186,8 @@ public extension Request where RawResource == SmartUnwrap, FinalResource: Sequence, FinalResource: Decodable, - FinalResource.Element: Decodable + FinalResource.Element: Decodable, + FinalResource.Element: Sendable { func decode(_ data: Data?, defaultDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> RawResource { guard let data = data else { @@ -274,6 +276,6 @@ public extension Request where RawResource: Decodable, FallbackResource: Decodab } } -public struct Empty: Codable { +public struct Empty: Codable, Sendable { public static let data = "{}".data(using: .utf8)! } diff --git a/Netable/Netable/SmartUnwrap.swift b/Netable/Netable/SmartUnwrap.swift index 00aedee..5c75847 100644 --- a/Netable/Netable/SmartUnwrap.swift +++ b/Netable/Netable/SmartUnwrap.swift @@ -8,7 +8,7 @@ import Foundation -public struct SmartUnwrap: Decodable { +public struct SmartUnwrap: Decodable, Sendable where T: Sendable { public typealias DecodedType = T public var decodedType: DecodedType