diff --git a/VDS/Classes/Control.swift b/VDS/Classes/Control.swift index 53b2f7f4..eecc62a6 100644 --- a/VDS/Classes/Control.swift +++ b/VDS/Classes/Control.swift @@ -13,14 +13,19 @@ import Combine open class Control: UIControl, ModelHandlerable, ViewProtocol, Resettable { @Published public var model: ModelType - private var cancellable: AnyCancellable? + private var cancellables = Set() + private var shouldUpdate: Bool = false open func set(with model: ModelType) { self.model = model } - open func onStateChange(viewModel: ModelType) { - + open func shouldUpdateView(viewModel: ModelType) -> Bool { + fatalError("Implement shouldUpdateView") + } + + open func updateView(viewModel: ModelType) { + fatalError("Implement updateView") } //-------------------------------------------------- @@ -58,9 +63,23 @@ open class Control: UIControl, ModelHandlerable, ViewProto public func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true - cancellable = $model.debounce(for: .seconds(Constants.ModelStateDebounce), scheduler: RunLoop.main).sink { [weak self] viewModel in - self?.onStateChange(viewModel: viewModel) - } + //setup shouldUpdate + $model.sink { [weak self] viewModel in + guard let self = self else { return } + let s = self.shouldUpdateView(viewModel: viewModel) + print("shouldUpdate - \(Self.self): \(s)") + self.shouldUpdate = s + }.store(in: &cancellables) + + //setup viewUpdate + $model.debounce(for: .seconds(Constants.ModelStateDebounce), scheduler: RunLoop.main).sink { [weak self] viewModel in + guard let self = self else { return } + if self.shouldUpdate { + self.updateView(viewModel: viewModel) + self.shouldUpdate = false + print("didUpdate - \(Self.self)") + } + }.store(in: &cancellables) setup() } } diff --git a/VDS/Classes/View.swift b/VDS/Classes/View.swift index fc587d60..7e1812cb 100644 --- a/VDS/Classes/View.swift +++ b/VDS/Classes/View.swift @@ -13,16 +13,21 @@ import Combine open class View: UIView, ModelHandlerable, ViewProtocol, Resettable { @Published public var model: ModelType - private var cancellable: AnyCancellable? - + private var cancellables = Set() + private var shouldUpdate: Bool = false + open func set(with model: ModelType) { self.model = model } - open func onStateChange(viewModel: ModelType) { - + open func shouldUpdateView(viewModel: ModelType) -> Bool { + fatalError("Implement shouldUpdateView") } + open func updateView(viewModel: ModelType) { + fatalError("Implement updateView") + } + //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -57,9 +62,24 @@ open class View: UIView, ModelHandlerable, ViewProtocol, R public func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true - cancellable = $model.debounce(for: .seconds(Constants.ModelStateDebounce), scheduler: RunLoop.main).sink { [weak self] viewModel in - self?.onStateChange(viewModel: viewModel) - } + //setup shouldUpdate + $model.sink { [weak self] viewModel in + guard let self = self else { return } + let s = self.shouldUpdateView(viewModel: viewModel) + print("shouldUpdate - \(Self.self): \(s)") + self.shouldUpdate = s + }.store(in: &cancellables) + + //setup viewUpdate + $model.debounce(for: .seconds(Constants.ModelStateDebounce), scheduler: RunLoop.main).sink { [weak self] viewModel in + guard let self = self else { return } + if self.shouldUpdate { + self.updateView(viewModel: viewModel) + self.shouldUpdate = false + print("didUpdate - \(Self.self)") + } + }.store(in: &cancellables) + setup() } } diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index 92670fc4..afc6f0b2 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -18,7 +18,8 @@ open class LabelBase: UILabel, ModelHandlerable, Initable // MARK: - Combine Properties //-------------------------------------------------- @Published public var model: ModelType - private var cancellable: AnyCancellable? + private var cancellables = Set() + private var shouldUpdate: Bool = false //-------------------------------------------------- // MARK: - Properties @@ -94,9 +95,23 @@ open class LabelBase: UILabel, ModelHandlerable, Initable translatesAutoresizingMaskIntoConstraints = false accessibilityCustomActions = [] accessibilityTraits = .staticText - cancellable = $model.debounce(for: .seconds(Constants.ModelStateDebounce), scheduler: RunLoop.main).sink { [weak self] viewModel in - self?.onStateChange(viewModel: viewModel) - } + + //setup shouldUpdate + $model.sink { [weak self] viewModel in + guard let self = self else { return } + self.shouldUpdate = self.shouldUpdateView(viewModel: viewModel) + print("shouldUpdate - \(Self.self): \(self.shouldUpdate)") + }.store(in: &cancellables) + + //setup viewUpdate + $model.debounce(for: .seconds(Constants.ModelStateDebounce), scheduler: RunLoop.main).sink { [weak self] viewModel in + guard let self = self else { return } + if self.shouldUpdate { + self.updateView(viewModel: viewModel) + self.shouldUpdate = false + print("didUpdate - \(Self.self)") + } + }.store(in: &cancellables) } public func reset() { @@ -120,7 +135,15 @@ open class LabelBase: UILabel, ModelHandlerable, Initable //-------------------------------------------------- /// Follow the SwiftUI View paradigm /// - Parameter viewModel: state - open func onStateChange(viewModel: ModelType) { + open func shouldUpdateView(viewModel: ModelType) -> Bool { + return viewModel.text != model.text + || viewModel.disabled != model.disabled + || viewModel.surface != model.surface + || viewModel.font != model.font + || viewModel.textPosition != model.textPosition + } + + open func updateView(viewModel: ModelType) { textAlignment = viewModel.textPosition.textAlignment textColor = textColorConfiguration.getColor(viewModel) @@ -146,7 +169,7 @@ open class LabelBase: UILabel, ModelHandlerable, Initable attribute.setAttribute(on: mutableText) //see if the attribute is Actionable - if let actionable = attribute as? LabelAttributeActionable{ + if let actionable = attribute as? any LabelAttributeActionable{ //create a accessibleAction let customAccessibilityAction = customAccessibilityAction(range: actionable.range) diff --git a/VDS/Components/SelectorBase/SelectorBase.swift b/VDS/Components/SelectorBase/SelectorBase.swift index 34678aed..b75d2791 100644 --- a/VDS/Components/SelectorBase/SelectorBase.swift +++ b/VDS/Components/SelectorBase/SelectorBase.swift @@ -300,7 +300,11 @@ open class SelectorBase: Control, Changable //-------------------------------------------------- /// Follow the SwiftUI View paradigm /// - Parameter viewModel: state - open override func onStateChange(viewModel: ModelType) { + open override func shouldUpdateView(viewModel: ModelType) -> Bool { + return true + } + + open override func updateView(viewModel: ModelType) { let enabled = !viewModel.disabled updateLabels(viewModel) diff --git a/VDS/Protocols/ModelHandlerable.swift b/VDS/Protocols/ModelHandlerable.swift index 3943ff61..49a79416 100644 --- a/VDS/Protocols/ModelHandlerable.swift +++ b/VDS/Protocols/ModelHandlerable.swift @@ -6,10 +6,13 @@ // import Foundation - + public protocol ModelHandlerable { associatedtype ModelType: Modelable var model: ModelType { get set } + init(with model: ModelType) func set(with model: ModelType) + func shouldUpdateView(viewModel: ModelType) -> Bool + func updateView(viewModel: ModelType) }