Skip to content

Make update a protocol#41

Merged
gordonbrander merged 10 commits into
mainfrom
2023-11-21-update-protocol
Nov 30, 2023
Merged

Make update a protocol#41
gordonbrander merged 10 commits into
mainfrom
2023-11-21-update-protocol

Conversation

@gordonbrander
Copy link
Copy Markdown
Collaborator

@gordonbrander gordonbrander commented Nov 29, 2023

  • Store requires Model.update to return some type that conforms to UpdateProtocol.
  • Update<Model> becomes a concrete implementation of UpdateProtocol
  • Users of ObservableStore are free to define custom update types that carry additional information, e.g. state change metadata for UIKit UIViewControllers.
  • Publish updates from Store.updates publisher. Updates are guaranteed to publish after state change.
    • Useful for driving UIViewControllers.

This is a non-breaking change for existing consumers of ObservableStore. The motivating reason for the change is that we wished to use ObservableStore to power complex UIViewControllers in Subconscious, where a diffing-based approach was not practicable. Allowing for the customization of Update lets individual implementations of Store provide additional metadata to controllers.

While working on this PR, I also discovered a simpler way to implement effects that does not require us to dynamically manage cancellables, by using flatMap to consume batches of fx.

...and receive actions on main, only updating state on main.
Update becomes a concrete implementation of UpdateProtocol. This enables
ObservableStore models to describe custom update structs that contain
additioanl information.
- Remove fx runner
- Run send synchronously to avoid breaking change
- Publish updates separately *after* state transaction is complete
- Revert tests to synchronous
- Add optional logging (off by default)
This prevents name ambiguity with Update<Model>, which was tripping up
Swift's type inference
{
/// Stores cancellables by ID
private(set) var cancellables: [UUID: AnyCancellable] = [:]
private var cancelTransactions: AnyCancellable?
Copy link
Copy Markdown

@bfollington bfollington Nov 30, 2023

Choose a reason for hiding this comment

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

This doesn't seem to be used anywhere anymore?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Combine subscribers automatically cancel when their cancellable is released. So you have to hold on to the cancellable to keep the subscriber alive. We hold on to the cancellable within the instance so that its lifetime matches the store lifetime. The subscriber will continue receiving as long as the store instance exists.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Update: after talking through, there was a confusion. The OP is in response to the fact that cancelTransactions is an additional cancellable property that doesn't need to be there. Followed up with fix in #43.

Comment on lines +224 to +229
private var fx: AnyPublisher<Model.Action, Never> {
_fxBatches
.flatMap({ publisher in publisher })
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
Copy link
Copy Markdown

@bfollington bfollington Nov 30, 2023

Choose a reason for hiding this comment

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

heck yeah 🙌

Comment thread Package.swift Outdated
let package = Package(
name: "ObservableStore",
platforms: [.macOS(.v10_15), .iOS(.v15)],
platforms: [.macOS(.v10_15), .iOS(.v16)],
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is this a required bump? I haven't got a problem with raising the target to iOS 16 just curious if a particular API motivated this change.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch. I thought it would be required for some of the changes I would make, but it turned out it was not needed. Backed it out.

Copy link
Copy Markdown

@bfollington bfollington left a comment

Choose a reason for hiding this comment

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

LGTM, but I would like to see that unused cancellable removed before merge (if it is really unused)

@gordonbrander gordonbrander merged commit c85e83d into main Nov 30, 2023
gordonbrander added a commit that referenced this pull request Nov 30, 2023
bfollington pushed a commit that referenced this pull request Nov 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants