New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resolve Compile Errors with Strict Swift Concurrency Checking #214
base: main
Are you sure you want to change the base?
Conversation
@@ -101,7 +102,7 @@ struct AnalyticsEventData: Encodable { | |||
self.correlationID = correlationID | |||
} | |||
|
|||
func encode(to encoder: Encoder) throws { | |||
nonisolated func encode(to encoder: Encoder) throws { | |||
var topLevel = encoder.container(keyedBy: TopLevelKeys.self) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This just gave warning during compile time but caused failure in Cocoapods test in the pipeline.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious if you could add the Sendable protocol to this struct to resolve this issue?
struct AnalyticsEventData: Encodable, Sendable {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it does not.
@@ -49,7 +49,7 @@ public struct AnalyticsService { | |||
do { | |||
let clientID = coreConfig.clientID | |||
|
|||
let eventData = AnalyticsEventData( | |||
let eventData = await AnalyticsEventData( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
q: This is an asynchronous constructor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because AnalyticsEventData was marked with @mainactor, to instantiate it in async function that isn't isolated to the @mainactor, I needed "await".
It seems like there is also an intermediary |
I checked with Targeted option and we have no errors or warnings other than same old warnings without the concurrency checking. I think for the compile errors with complete option, the only breaking change would be for the buttons if merchant is not instantiating them on main thread. I think marking AnalyticsEventData @mainactor is ok since the work in there is lightweight. Alternative would be to fetch device information somewhere else and store it for access here, I don't see an obvious place to store the info. I can implement something like DeviceInfoCache. I thought @mainactor was the simplest way to deal with compile errors. I think it would be surprising if any version of Swift in the future would enforce this one, any reference to UIDevice's read only properties, for example, giving compile errors without explicit main thread context. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the test updates that we needed to make an indication at all that these would be a breaking change for merchants or are these changes mainly behind the scenes? What changes would this cause for merchant demo apps that also have swift strict concurrency checking enabled?
I also don't see anywhere in this PR where we are enabling this setting. Will that be in a future PR along with a changelog entry if needed?
@@ -5,6 +5,7 @@ import AuthenticationServices | |||
@testable import CardPayments | |||
@testable import TestShared | |||
|
|||
@MainActor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the tests, it looks like we may have the opportunity to make the test async and await on waitForExpectations
instead (from this swift forum). Not sure if you've had a chance to try this yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in bd8cd78
@@ -161,6 +161,7 @@ public class CardClient: NSObject { | |||
|
|||
extension CardClient: ASWebAuthenticationPresentationContextProviding { | |||
|
|||
@MainActor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious what portion of this method needs to be called on the main thread. Is it our default to ASPresentationAnchor
if we cannot find a window or something else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We start the authentication session on the main thread in the start function.
Since UIApplication is marked @mainactor, there is compile error with accessing its properties in this function with complete checking option since it checks for explicit main thread context. This seems extreme to me, as it would break many implementations for others as well.
The AnalyticEventData change, I think that's just us, so no breaking change for merchant. PresentationAnchor change, that function is used behind the scenes as part of ASWebAuthenticationSession, so I don't think it will affect merchants' implementations. It would only be problematic if merchant has the strict checking and we don't. I didn't submit the complete concurrency checking option but I fixed compile errors that occurred as a result of that option check. |
Personally, I think if we are adding the code to support complete strict concurrency checking, we should enable it in the SDK at the same time. This way it is clear to merchants/us when we added support and what the necessary code changes were. But curious to hear how other folks feel. |
@KunJeongPark I just came across this Swift Forum thread on Swift 6. There are a few things of note with regards to this PR:
Based on these comments and since we do not have a major version planned to update to either Swift 5.10 (that includes some of these fixes) or Swift 6 (that does not yet have a targeted release date) it seems like we should hold off on these changes until the lauguage has ironed out some of these bugs. Curious to know what other folks think! |
Those are great finds from the forums. I agree, I did have a conversation with some people and consensus is to mark possible issues and keep the branches updated periodically and revisit as warnings and errors in Xcode get refined for next versions. I will keep making changes, checking forums, keeping the branches updated and I look forward to input from all of you whenever you have a chance. I think it's good for us to be ahead of it and start thinking about possible issues. |
Reason for changes
Apple has suggested you work towards complete checking, not just to avoid potential problems, but also in preparation for the expected checking that a future release of Swift 6 will enforce.
In WWDC 2022 video "Eliminate data races using Swift Concurrency", they state "Complete checking approximates the intended Swift 6 semantics to completely eliminate data races".
Summary of changes
References to properties in UIDevice, UIApplication in structs or classes result in an error unless
the struct or classes or specific functions are referencing these properties are also explicitly guaranteed to run
on main thread.
Unit tests using waitForExpectations function needed to be annotated with @mainactor to resolve compile errors
In PaymentButton's subclasses, their Representable structs that wrap the UIKit elements for SwiftUI views, needed to have initializers that are annotated @mainactor to resolve compile errors.
PaymentButton is a subclass of UIButton which is annotated as @mainactor. I think it is not enforced for the UIButton subclass initializers because of backward compatibility.
I will address some Sendable warnings in another PR.
We can decide when we want to implement these changes.
It's good to be proactive in at least spiking potential scope of work before Swift 6.
Checklist
- [ ] Added a changelog entryAuthors