From 24a33a0b9e91de937af96f4087c603f9df9e8aca Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 12 Aug 2022 15:24:29 -0500 Subject: [PATCH] added ModelHandlerPublisher Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 4 ++ VDS/Classes/ModelHandlerPublisher.swift | 66 +++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 VDS/Classes/ModelHandlerPublisher.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 29b77773..5ae7d63b 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -44,6 +44,7 @@ EAB1D29E28A5619500DAE764 /* RadioButtonGroupModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D29D28A5619500DAE764 /* RadioButtonGroupModel.swift */; }; EAB1D2A128A598FE00DAE764 /* UsesAutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2A028A598FE00DAE764 /* UsesAutoLayout.swift */; }; EAB1D2A328A5994800DAE764 /* Debuggable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2A228A5994800DAE764 /* Debuggable.swift */; }; + EAB1D2C728A6E76300DAE764 /* ModelHandlerPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2C628A6E76300DAE764 /* ModelHandlerPublisher.swift */; }; EAF7F0952899861000B287F5 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0932899861000B287F5 /* Checkbox.swift */; }; EAF7F0962899861000B287F5 /* CheckboxModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0942899861000B287F5 /* CheckboxModel.swift */; }; EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0992899B17200B287F5 /* CATransaction.swift */; }; @@ -124,6 +125,7 @@ EAB1D29D28A5619500DAE764 /* RadioButtonGroupModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonGroupModel.swift; sourceTree = ""; }; EAB1D2A028A598FE00DAE764 /* UsesAutoLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsesAutoLayout.swift; sourceTree = ""; }; EAB1D2A228A5994800DAE764 /* Debuggable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Debuggable.swift; sourceTree = ""; }; + EAB1D2C628A6E76300DAE764 /* ModelHandlerPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelHandlerPublisher.swift; sourceTree = ""; }; EAF7F0932899861000B287F5 /* Checkbox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = ""; }; EAF7F0942899861000B287F5 /* CheckboxModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxModel.swift; sourceTree = ""; }; EAF7F0992899B17200B287F5 /* CATransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CATransaction.swift; sourceTree = ""; }; @@ -298,6 +300,7 @@ EAF7F09D289AAEC000B287F5 /* Constants.swift */, EA3361B5288B2A410071C351 /* Control.swift */, EAF7F09F289AB7EC00B287F5 /* View.swift */, + EAB1D2C628A6E76300DAE764 /* ModelHandlerPublisher.swift */, ); path = Classes; sourceTree = ""; @@ -558,6 +561,7 @@ EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */, EA336171288B19200071C351 /* VDS.docc in Sources */, EAF7F0962899861000B287F5 /* CheckboxModel.swift in Sources */, + EAB1D2C728A6E76300DAE764 /* ModelHandlerPublisher.swift in Sources */, EA3361AA288B25E40071C351 /* Disabling.swift in Sources */, EA3361B6288B2A410071C351 /* Control.swift in Sources */, EAB1D2A328A5994800DAE764 /* Debuggable.swift in Sources */, diff --git a/VDS/Classes/ModelHandlerPublisher.swift b/VDS/Classes/ModelHandlerPublisher.swift new file mode 100644 index 00000000..07077184 --- /dev/null +++ b/VDS/Classes/ModelHandlerPublisher.swift @@ -0,0 +1,66 @@ +// +// ModelHanlderPublisher.swift +// VDS +// +// Created by Matt Bruce on 8/12/22. +// + +import Foundation +import Combine + +extension Publishers { + public struct ModelHandlerPublisher: Publisher { + + public typealias Output = ModelHandlerType.ModelType + public typealias Failure = Never + + private let modelHandler: ModelHandlerType + + public init(modelHandler: ModelHandlerType) { self.modelHandler = modelHandler } + + public func receive(subscriber: S) where S : Subscriber, Never == S.Failure, ModelHandlerType.ModelType == S.Input { + let subscription = ModelHandlerSubscription(subscriber: subscriber, modelHandler: modelHandler) + subscriber.receive(subscription: subscription) + } + } + + public class ModelHandlerSubscription: Subscription where S.Input == ModelHandlerType.ModelType, S.Failure == Never { + + private var subscriber: S? + private var modelHandler: ModelHandlerType? + public var subscribers = Set() + public init(subscriber: S, modelHandler: ModelHandlerType) { + self.subscriber = subscriber + self.modelHandler = modelHandler + subscribe() + } + + public func request(_ demand: Subscribers.Demand) { } + + public func cancel() { + subscriber = nil + modelHandler = nil + } + + private func subscribe() { + guard let publisher = modelHandler?.modelPublisher else { return } + + publisher.debounce(for: .seconds(Constants.ModelStateDebounce), scheduler: RunLoop.main).sink { [weak self] viewModel in + guard let self else { return } + _ = self.subscriber?.receive(viewModel) + }.store(in: &subscribers) + } + } +} + +extension ModelHandlerPublishable { + public var handlerPublisher: Publishers.ModelHandlerPublisher { + return Publishers.ModelHandlerPublisher(modelHandler: self) + } + + public func createBinding(with subject: CurrentValueSubject, storeIn subscriptions: inout Set) { + handlerPublisher.sink { (value) in + subject.send(value) + }.store(in: &subscriptions) + } +}