-
Notifications
You must be signed in to change notification settings - Fork 57
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
Swift concurrency #29
base: main
Are you sure you want to change the base?
Conversation
@rcasula Thanks for looking into this! We definitely have plans to adopt this new style soon, but haven't had time to look into it. This looks good! Just a couple things we need to figure out in the future:
Going to keep this open for now while we find the time to figure out those details. Thanks for getting this work started though! |
5f8e855
to
45c805e
Compare
Hey, what is the status of this PR? What needs to be done to wrap up the new release? |
manager.dismissHeadingCalibrationDisplay() | ||
#endif | ||
delegate: { | ||
AsyncStream { continuation in |
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.
Given Dependencies
define global instances, I think we need to ensure all dependencies' APIs support being called from multiple places of the application, possibly simultaneously/concurrently.
As it is, every time delegate
is called, a new LocationManagerDelegate
is created which will make any previous returned delegate
stream not receive any new events. There's also the issue of CLLocationManager.delegate
not being atomic
on iOS, which can result in data races.
A possible solution for this could be to return a new stream for each caller, with the difference that all streams would share a single LocationManagerDelegate
instance underneath that would be set as the single CLLocationManager.delegate
(possibly when CLLocationManager
is instantiated, avoiding data races). The LocationManagerDelegate
could be made an actor
managing a collection of streams (creation/deletion), forwarding delegate events accordingly.
Does this make sense? I can try to give this a go.
PS: Thanks for the awesome work 🙏🏼
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.
In the meantime, opened MR rcasula#2 which hopefully (also) addresses this issue 🤓
37d0d45
to
ca60abb
Compare
For completeness' sake, following a discussion in this PF's slack thread, to ensure It appears to ensure Seems like an interesting approach, but ideally someone with more experience in swift concurrency can chime in, or at least we have one more approach to consider 🤓 |
@rcasula can this MR be marked as ready for review? What documentation updates are missing? Thanks! |
Package.swift
Outdated
// "-Xfrontend", "-enable-actor-data-race-checks", | ||
// ]) | ||
// ) | ||
//} |
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.
Should it be enabled?
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.
If we do, SPM complains about unsafe flags being used when integrating it in other packages/projects
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.
ohh, that's a good point. Just thinking loud here. What if we introduce ENV varible for local development and CI.
Something like :
if ProcessInfo.processInfo.environment["COMPOSABLE_DEVELOPER"] == "1" {
settings.append(.unsafeFlags([
"-Xfrontend",
"-warn-concurrency",
"-Xfrontend",
"-enable-actor-data-race-checks"
]))
}
Little incovinience to define variable locally but it can be documented on the README for developers.
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.
That's definitely an interesting idea! Let's see what the rest have to say 🤓
friendly ping, can we please get an feedback? |
Hello, any chances to proceed with it? |
When testing the current (Swift Concurrency) approach, the delegate method calls were not being invoked, and after some investigation it seems the problem was related with the `RunLoop` in which the `CLLocationManager` was created. With the latest `Dependencies`/`TCA` implementations, dependencies' access isn't bound to the `@MainActor`, so code is run from arbitrary queues/threads spanning multiple RunLoops. According to `CLLocationManager`'s [documentation](https://developer.apple.com/documentation/corelocation/cllocationmanager): > "Core Location calls the methods of your delegate object using the > `RunLoop` of the thread on which you initialized the > `CLLocationManager` object. By forcing the `LocationManager.live`'s `CLLocationManager` instance to be instantiated on the main `RunLoop` via `@MainActor`, the delegate methods are correctly invoked. To minimize problems, all `.live` instance APIs' closures were annotated with `@MainActor`. Furthermore, as the `Dependencies` instances are shared and can be called from multiple places concurrently, the `LocationManagerDelegate` was updated to allow forwarding delegate calls to multiple streams provided via `delegate()`. Ran `swift-format` and performed some cleanups.
- Enable swift concurrency warnings in `Package.swift` - Add `Sendable` conformance where needed, and wrap `CLLocation` types in `@UncheckedSendable` until properly annotated.
40a98e1
to
363839a
Compare
Thank you @rcasula, you saved my day 🍻 |
Update the Library to the new swift-concurrency standard.
I was thinking if removing the composable architecture dependency makes sense.
This PR is still in draft because I have to:
Please let me know if this PR is any good!