Skip to content

Commit

Permalink
Support Multiple Publishers (again)
Browse files Browse the repository at this point in the history
  • Loading branch information
EmilioPelaez committed Jan 2, 2025
1 parent d5edd14 commit f9ca3ea
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct EventPublisherModifier<E: Event>: ViewModifier {

func body(content: Content) -> some View {
content
.publisherRegistrar(for: E.self, id: id, childContainers: $containers)
.publisherRegistrar(for: E.self, id: id, publisher: nil, containers: $containers)
.onAppearAndChange(of: containers) { containers in
updatePublisher(containers: containers, destination: destination)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import SwiftUI
*/
struct EventSubscriberModifier<E: Event>: ViewModifier {
@Environment(\.eventSubscriptionRegistrars) var registrars
@Environment(\.responderSafetyLevel) var safetyLevel

let id: String
let publisher: EventPublisher<E>
Expand All @@ -34,30 +33,7 @@ struct EventSubscriberModifier<E: Event>: ViewModifier {

func body(content: Content) -> some View {
content
.publisherRegistrar(for: E.self, id: id, childContainers: $containers)
.onAppearAndChange(of: registrars) { registrars in
registerPublisher(registrars, containers: containers)
}
.onAppearAndChange(of: containers) { containers in
registerPublisher(registrars, containers: containers)
}
.onDisappear(perform: unregisterPublisher)
}

func registerPublisher(_ registrars: RegistrarDictionary, containers: Set<PublishersContainer>) {
guard let registrar = registrars[ObjectIdentifier(E.self)] else {
let message = "Subscribed to event with no publisher: \(String(describing: E.self))"
switch safetyLevel {
case .strict: fatalError(message)
case .relaxed: return print(message)
case .disabled: return
}
}
let container = PublishersContainer(id: id, publisher: publisher, containers: containers)
registrar.register(container.id, container)
}

func unregisterPublisher() {
registrars[ObjectIdentifier(E.self)]?.register(id, nil)
.publisherRegistrar(for: E.self, id: id, publisher: publisher, containers: $containers)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,32 @@
import SwiftUI

extension View {
func publisherRegistrar<E: Event>(for event: E.Type, id: String, childContainers: Binding<Set<PublishersContainer>>) -> some View {
modifier(PublisherRegistrarModifier(event: event, id: id, childContainers: childContainers))
func publisherRegistrar<E: Event>(for event: E.Type,
id: String,
publisher: EventPublisher<E>?,
containers: Binding<Set<PublishersContainer>>) -> some View {
modifier(PublisherRegistrarModifier(event: event,
id: id,
publisher: publisher,
containers: containers))
}
}

struct PublisherRegistrarModifier<E: Event>: ViewModifier {
@Environment(\.responderSafetyLevel) var safetyLevel
@Environment(\.eventSubscriptionRegistrars) var registrars

let id: String
@Binding var childContainers: Set<PublishersContainer>
let publisher: EventPublisher<E>?
@Binding var containers: Set<PublishersContainer>

@State var registrar: EventSubscriptionRegistrar

init(event: E.Type, id: String, childContainers: Binding<Set<PublishersContainer>>) {
init(event: E.Type, id: String, publisher: EventPublisher<E>?, containers: Binding<Set<PublishersContainer>>) {
self.id = id
self._childContainers = childContainers
self._registrar = .init(initialValue: .init(id: id) { _, _ in })
self.publisher = publisher
self._containers = containers
self._registrar = .init(initialValue: .init(id: id + "-empty") { _, _ in })
}

var updatedRegistrars: [ObjectIdentifier: EventSubscriptionRegistrar] {
Expand All @@ -36,16 +45,42 @@ struct PublisherRegistrarModifier<E: Event>: ViewModifier {
func body(content: Content) -> some View {
content
.onAppear(perform: createRegistrar)
.onAppearAndChange(of: registrars) { registrars in
registerPublisher(registrars, containers: containers)
}
.onAppearAndChange(of: containers) { containers in
registerPublisher(registrars, containers: containers)
}
.environment(\.eventSubscriptionRegistrars, updatedRegistrars)
.onDisappear(perform: unregisterPublisher)
}

func createRegistrar() {
registrar = .init(id: id) { id, container in
if let container {
childContainers.update(with: container)
} else if let container = childContainers.first(where: { $0.id == id }) {
childContainers.remove(container)
containers.update(with: container)
} else if let container = containers.first(where: { $0.id == id }) {
containers.remove(container)
}
}
}

func registerPublisher(_ registrars: RegistrarDictionary, containers: Set<PublishersContainer>) {
guard let registrar = registrars[ObjectIdentifier(E.self)] else {
if publisher == nil { return } // We're on a publisher modifier
let message = "Subscribed to event with no publisher: \(String(describing: E.self))"
switch safetyLevel {
case .strict: fatalError(message)
case .relaxed: return print(message)
case .disabled: return
}
}
let publisher = self.publisher ?? EventPublisher(id: id) { _ in }
let container = PublishersContainer(id: id, publisher: publisher, containers: containers)
registrar.register(container.id, container)
}

func unregisterPublisher() {
registrars[ObjectIdentifier(E.self)]?.register(id, nil)
}
}

0 comments on commit f9ca3ea

Please sign in to comment.