Skip to content
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

[ADD] refined combine API #38

Merged
merged 12 commits into from
Jan 21, 2022
Merged

[ADD] refined combine API #38

merged 12 commits into from
Jan 21, 2022

Conversation

JonnyBeeGod
Copy link
Collaborator

@JonnyBeeGod JonnyBeeGod commented Dec 25, 2021

Have you read the Contributing Guidelines?

Issue # (no issue yet, can be created if needed)

Describe your changes

This PR removes the need for the .publisher(for:) KVO API call, the NSObject inheritance and the @objc dynamic annotations by making use of the projectedValue property of the property wrappers. See https://www.avanderlee.com/swift/property-wrappers/#projecting-a-value-from-a-property-wrapper for more details on this topic. Please note that I like to use CurrentValueSubject instead of PassthroughSubject as this makes sure our publisher is stateful and immediately publishes the currently saved value on sink. If we would use PassthroughSubject instead, receiveValue would only fire after the value has been updated again.

This is only a draft PR as this makes discussion way easier rather than describing this change in an issue. Also the example view needs more works and was just thrown together quickly to be able to test the combine API without interference of the manually triggered tableView.reloadRows calls after each update of the values.

Also note the updated deployment targets. This would be required in order to be able to use the Combine publishers

Please let me know what you think

@jessesquires
Copy link
Owner

Thanks @JonnyBeeGod!

Overall this looks good. 💯

My only hesitation is bumping the minimum deployment targets, which will require a major version update (to 3.0), but maybe that's not terrible since clients can just use the 2.0 version indefinitely...

Foil.xcodeproj/project.pbxproj Show resolved Hide resolved
Sources/WrappedDefault.swift Outdated Show resolved Hide resolved
Sources/WrappedDefault.swift Outdated Show resolved Hide resolved
Sources/WrappedDefaultOptional.swift Outdated Show resolved Hide resolved
Tests/ObservationTests.swift Show resolved Hide resolved
@JonnyBeeGod
Copy link
Collaborator Author

Thanks @JonnyBeeGod!

Overall this looks good. 💯

My only hesitation is bumping the minimum deployment targets, which will require a major version update (to 3.0), but maybe that's not terrible since clients can just use the 2.0 version indefinitely...

That's great to hear! I updated the PR with your comments, the only thing left would be the example project where I am uncertain on how to proceed. The current example on main branch does not use combine, we could either rewrite it or extend my quickly thrown together Combine example (and maybe also showcase SwiftUI integration). What do you think?

@jessesquires jessesquires marked this pull request as ready for review December 30, 2021 02:34
@jessesquires jessesquires added this to the NEXT milestone Dec 30, 2021
@jessesquires
Copy link
Owner

I updated the PR with your comments

Thank you! 🙌🏼 Everything is looking good to me. 😎

the only thing left would be the example project where I am uncertain on how to proceed. The current example on main branch does not use combine, we could either rewrite it or extend my quickly thrown together Combine example (and maybe also showcase SwiftUI integration). What do you think?

I'll try to checkout your branch and take a look, then decide. Overall, I think this is mostly ready to go, but I've only done a quick review -- I'll take a closer look soon.

I'm a bit busy with the holidays and such -- but I really appreciate this contribution! 😊

@nolanw
Copy link
Collaborator

nolanw commented Jan 12, 2022

If Foil changes to vend a publisher via projectedValue, is there any way that publisher could be a UserDefaults KVO publisher for the given key? That would let changes that don't flow through the wrapped property (e.g. another wrapped property with the same key, direct UserDefaults usage, or out-of-process changes to defaults in an app container) notify subscribers to the Foil-wrapped property's publisher.

I'm not sure how to construct a correctly-typed KeyPath to give to the KeyValueObservingPublisher. But if there is some approach that could work with an arbitrary string key (custom publisher doing its own KVO?), the resulting publisher would be more useful and would obviate one way it's currently possible to misuse Foil.

Otherwise, the currently suggested @objc dynamic approach seems more useful than vending a Subject because it allows for Objective-C interoperability.

@jessesquires
Copy link
Owner

If Foil changes to vend a publisher via projectedValue, is there any way that publisher could be a UserDefaults KVO publisher for the given key?

Thanks for the feedback @nolanw! I'm not entirely sure I'm following here. @JonnyBeeGod can you help?


Also, I'm hoping I can circle back to this by the end of this week and get this change landed. 😄

@nolanw
Copy link
Collaborator

nolanw commented Jan 20, 2022

I kinda went off into the weeds there. More concisely:

The current implementation in this PR adds a CurrentValueSubject to the property wrapper. This works great when the decorated property is mutated, but it misses changes that occur to the underlying UserDefaults value by other means. I was wondering aloud if there's some way to obtain a publisher directly from UserDefaults, because that would capture all changes for the key.

It's certainly not worth holding up this PR, just an idea to ponder. Since the projected value is an AnyPublisher, we can always change it later. If I give my idea a try, I'll open a new PR. Sorry for hijacking this one!

@jessesquires
Copy link
Owner

@nolanw ah, I see what you mean. 💯

Yes, to accommodate the scenario you describe, you would need a centralized mechanism to access all user defaults.

I believe our suggested usage for Foil in the docs resolves this by creating an AppSettings.shared object through which all settings are accessed and modified. See: https://github.com/jessesquires/Foil#using-combine

This PR is essentially just simplifying the existing pattern by allowing you to omit the call to .publisher(for: ).

But, in any case, yes -- feel free to open a new issue to discuss further! 😊

Copy link
Owner

@jessesquires jessesquires left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright @JonnyBeeGod -- I just pushed a few minor changes. This is ready to go 💯

I'll set it to merge automatically and I'll work on releasing 3.0 by next week.

@jessesquires jessesquires enabled auto-merge (squash) January 21, 2022 23:28
@jessesquires jessesquires mentioned this pull request Jan 21, 2022
7 tasks
@jessesquires
Copy link
Owner

Hm. I think the test failures are flakes. I will address them in #39 before tagging the new release.

@jessesquires jessesquires merged commit 5fb292c into jessesquires:main Jan 21, 2022
@jessesquires
Copy link
Owner

jessesquires commented Jan 21, 2022

@JonnyBeeGod I've also invited you to be a collaborator on this project. 😄

@JonnyBeeGod
Copy link
Collaborator Author

@JonnyBeeGod I've also invited you to be a collaborator on this project. 😄

Hey thank you very much :) The invitation already expired but I would still very much like to be a contributor.

@jessesquires
Copy link
Owner

@JonnyBeeGod -- resent!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants