diff --git a/VDS/BaseClasses/Control.swift b/VDS/BaseClasses/Control.swift index b2f3d4ae..5d839316 100644 --- a/VDS/BaseClasses/Control.swift +++ b/VDS/BaseClasses/Control.swift @@ -46,13 +46,13 @@ open class Control: UIControl, ViewProtocol, UserInfoable, Clickable { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- + internal var updateWorkItem: DispatchWorkItem? + private var initialSetupPerformed = false //-------------------------------------------------- // MARK: - Public Properties - //-------------------------------------------------- - open var shouldUpdateView: Bool = true - + //-------------------------------------------------- open var userInfo = [String: Primitive]() open var surface: Surface = .light { didSet { setNeedsUpdate() } } diff --git a/VDS/BaseClasses/Selector/SelectorItemBase.swift b/VDS/BaseClasses/Selector/SelectorItemBase.swift index 9ca86d8c..60e56e25 100644 --- a/VDS/BaseClasses/Selector/SelectorItemBase.swift +++ b/VDS/BaseClasses/Selector/SelectorItemBase.swift @@ -205,7 +205,6 @@ open class SelectorItemBase: Control, Errorable, /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false label.reset() childLabel.reset() errorLabel.reset() @@ -225,9 +224,6 @@ open class SelectorItemBase: Control, Errorable, inputId = nil value = nil isSelected = false - - shouldUpdateView = true - setNeedsUpdate() } //-------------------------------------------------- diff --git a/VDS/BaseClasses/View.swift b/VDS/BaseClasses/View.swift index 89e5ce4b..1ac99690 100644 --- a/VDS/BaseClasses/View.swift +++ b/VDS/BaseClasses/View.swift @@ -39,13 +39,13 @@ open class View: UIView, ViewProtocol, UserInfoable { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- + internal var updateWorkItem: DispatchWorkItem? + private var initialSetupPerformed = false //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - open var shouldUpdateView: Bool = true - /// Dictionary for keeping information for this Control use only Primitives. open var userInfo = [String: Primitive]() diff --git a/VDS/Components/Badge/Badge.swift b/VDS/Components/Badge/Badge.swift index 67bbae67..d09e0f6f 100644 --- a/VDS/Components/Badge/Badge.swift +++ b/VDS/Components/Badge/Badge.swift @@ -150,7 +150,6 @@ open class Badge: View { /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false label.reset() label.lineBreakMode = .byTruncatingTail label.textStyle = .boldBodySmall @@ -158,8 +157,6 @@ open class Badge: View { text = "" maxWidth = nil numberOfLines = 1 - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/BadgeIndicator/BadgeIndicator.swift b/VDS/Components/BadgeIndicator/BadgeIndicator.swift index 45432458..91bcfbba 100644 --- a/VDS/Components/BadgeIndicator/BadgeIndicator.swift +++ b/VDS/Components/BadgeIndicator/BadgeIndicator.swift @@ -296,14 +296,11 @@ open class BadgeIndicator: View { /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false label.reset() label.lineBreakMode = .byTruncatingTail label.textAlignment = .center fillColor = .red number = nil - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/Buttons/Button/Button.swift b/VDS/Components/Buttons/Button/Button.swift index 81f10b6e..535cd3fd 100644 --- a/VDS/Components/Buttons/Button/Button.swift +++ b/VDS/Components/Buttons/Button/Button.swift @@ -155,12 +155,9 @@ open class Button: ButtonBase, Useable, Buttonable { /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false use = .primary width = nil size = .large - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/Buttons/ButtonBase.swift b/VDS/Components/Buttons/ButtonBase.swift index e505b7f8..a13419bb 100644 --- a/VDS/Components/Buttons/ButtonBase.swift +++ b/VDS/Components/Buttons/ButtonBase.swift @@ -67,14 +67,13 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- + internal var updateWorkItem: DispatchWorkItem? + private var initialSetupPerformed = false //-------------------------------------------------- // MARK: - Properties - //-------------------------------------------------- - /// Key of whether or not updateView() is called in setNeedsUpdate() - open var shouldUpdateView: Bool = true - + //-------------------------------------------------- /// The ButtonSize available to this type of Buttonable. open var availableSizes: [ButtonSize] { [] } @@ -156,13 +155,10 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { } open func reset() { - shouldUpdateView = false surface = .light isEnabled = true text = nil accessibilityCustomActions = [] - shouldUpdateView = true - setNeedsUpdate() } //-------------------------------------------------- diff --git a/VDS/Components/Buttons/TextLink/TextLink.swift b/VDS/Components/Buttons/TextLink/TextLink.swift index 556c2c63..7c85b472 100644 --- a/VDS/Components/Buttons/TextLink/TextLink.swift +++ b/VDS/Components/Buttons/TextLink/TextLink.swift @@ -113,14 +113,11 @@ open class TextLink: ButtonBase, Buttonable { /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false text = nil size = .large accessibilityCustomActions = [] isAccessibilityElement = true accessibilityTraits = .link - shouldUpdateView = true - setNeedsUpdate() } } diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index 85e0ae6e..3b7516d5 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -280,7 +280,6 @@ open class ButtonIcon: Control { /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false kind = .ghost surfaceType = .colorFill size = .large @@ -288,8 +287,6 @@ open class ButtonIcon: Control { hideBorder = true iconOffset = .init(x: 0, y: 0) iconName = nil - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index d242c2e6..9b9dd9a1 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -42,6 +42,8 @@ open class Label: UILabel, ViewProtocol, UserInfoable { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- + internal var updateWorkItem: DispatchWorkItem? + private var initialSetupPerformed = false private var edgeInsets: UIEdgeInsets { textStyle.edgeInsets } @@ -100,9 +102,6 @@ open class Label: UILabel, ViewProtocol, UserInfoable { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - /// Key of whether or not updateView() is called in setNeedsUpdate() - open var shouldUpdateView: Bool = true - /// Determines if the label should use its own attributedText property instead of rendering the attributedText propert /// based of other local properties, such as textStyle, textColor, surface, etc... The default value is false. open var useAttributedText: Bool = false @@ -178,7 +177,6 @@ open class Label: UILabel, ViewProtocol, UserInfoable { open func setup() {} open func reset() { - shouldUpdateView = false surface = .light isEnabled = true attributes = nil @@ -188,8 +186,6 @@ open class Label: UILabel, ViewProtocol, UserInfoable { attributedText = nil numberOfLines = 0 backgroundColor = .clear - shouldUpdateView = true - setNeedsUpdate() } open func updateView() { diff --git a/VDS/Components/Notification/Notification.swift b/VDS/Components/Notification/Notification.swift index 274ad8af..fb60394e 100644 --- a/VDS/Components/Notification/Notification.swift +++ b/VDS/Components/Notification/Notification.swift @@ -255,8 +255,6 @@ open class Notification: View { open override func reset() { super.reset() - shouldUpdateView = false - titleLabel.reset() titleLabel.text = "" titleLabel.textStyle = UIDevice.isIPad ? .boldBodyLarge : .boldBodySmall @@ -280,9 +278,6 @@ open class Notification: View { layout = .vertical hideCloseButton = false - - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/RadioBox/RadioBoxItem.swift b/VDS/Components/RadioBox/RadioBoxItem.swift index 81f3f709..848059eb 100644 --- a/VDS/Components/RadioBox/RadioBoxItem.swift +++ b/VDS/Components/RadioBox/RadioBoxItem.swift @@ -206,7 +206,6 @@ open class RadioBoxItem: Control, Changeable, FormFieldable { /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false textLabel.reset() subTextLabel.reset() subTextRightLabel.reset() @@ -229,9 +228,6 @@ open class RadioBoxItem: Control, Changeable, FormFieldable { value = nil isSelected = false - - shouldUpdateView = true - setNeedsUpdate() } /// This will change the state of the Selector and execute the actionBlock if provided. diff --git a/VDS/Components/TileContainer/TileContainer.swift b/VDS/Components/TileContainer/TileContainer.swift index bad144e2..2e84cda3 100644 --- a/VDS/Components/TileContainer/TileContainer.swift +++ b/VDS/Components/TileContainer/TileContainer.swift @@ -234,7 +234,6 @@ open class TileContainer: Control { /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false color = .white padding = .padding4X aspectRatio = .ratio1x1 @@ -243,8 +242,6 @@ open class TileContainer: Control { height = nil showBorder = false showDropShadows = false - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/Tilelet/Tilelet.swift b/VDS/Components/Tilelet/Tilelet.swift index 657a735b..8ae2145e 100644 --- a/VDS/Components/Tilelet/Tilelet.swift +++ b/VDS/Components/Tilelet/Tilelet.swift @@ -253,7 +253,6 @@ open class Tilelet: TileContainer { /// Resets to default settings. open override func reset() { - shouldUpdateView = false aspectRatio = .none color = .black //models @@ -262,8 +261,6 @@ open class Tilelet: TileContainer { subTitleModel = nil descriptiveIconModel = nil directionalIconModel = nil - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/TitleLockup/TitleLockup.swift b/VDS/Components/TitleLockup/TitleLockup.swift index 2fdd5598..fc4d70c1 100644 --- a/VDS/Components/TitleLockup/TitleLockup.swift +++ b/VDS/Components/TitleLockup/TitleLockup.swift @@ -294,12 +294,9 @@ open class TitleLockup: View { /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false eyebrowModel = nil titleModel = nil subTitleModel = nil - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/Toggle/Toggle.swift b/VDS/Components/Toggle/Toggle.swift index a13cfdb9..ba215da8 100644 --- a/VDS/Components/Toggle/Toggle.swift +++ b/VDS/Components/Toggle/Toggle.swift @@ -216,7 +216,6 @@ open class Toggle: Control, Changeable, FormFieldable { /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false label.reset() isEnabled = true isOn = false @@ -229,8 +228,6 @@ open class Toggle: Control, Changeable, FormFieldable { textPosition = .left inputId = nil value = nil - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/Toggle/ToggleView.swift b/VDS/Components/Toggle/ToggleView.swift index f4d257d5..3715ebd2 100644 --- a/VDS/Components/Toggle/ToggleView.swift +++ b/VDS/Components/Toggle/ToggleView.swift @@ -155,15 +155,12 @@ open class ToggleView: Control, Changeable, FormFieldable { /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false isOn = false isAnimated = true inputId = nil value = nil toggleView.backgroundColor = toggleColorConfiguration.getColor(self) knobView.backgroundColor = knobColorConfiguration.getColor(self) - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/Tooltip/Tooltip.swift b/VDS/Components/Tooltip/Tooltip.swift index 679c260e..ffdf70d5 100644 --- a/VDS/Components/Tooltip/Tooltip.swift +++ b/VDS/Components/Tooltip/Tooltip.swift @@ -145,14 +145,11 @@ open class Tooltip: Control, TooltipLaunchable { /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false size = .medium title = "" content = "" fillColor = .primary closeButtonText = "Close" - shouldUpdateView = true - setNeedsUpdate() } /// Used to make changes to the View based off a change events or from local properties. diff --git a/VDS/Components/Tooltip/TrailingTooltipLabel.swift b/VDS/Components/Tooltip/TrailingTooltipLabel.swift index 4ea09a90..29e6f3bc 100644 --- a/VDS/Components/Tooltip/TrailingTooltipLabel.swift +++ b/VDS/Components/Tooltip/TrailingTooltipLabel.swift @@ -110,7 +110,6 @@ open class TrailingTooltipLabel: View, TooltipLaunchable { /// Resets to default settings. open override func reset() { super.reset() - shouldUpdateView = false labelText = nil labelAttributes = nil labelTextStyle = .defaultStyle @@ -118,8 +117,6 @@ open class TrailingTooltipLabel: View, TooltipLaunchable { tooltipCloseButtonText = "Close" tooltipTitle = "" tooltipContent = "" - shouldUpdateView = true - setNeedsUpdate() } } diff --git a/VDS/Protocols/ViewProtocol.swift b/VDS/Protocols/ViewProtocol.swift index da730372..3a52d004 100644 --- a/VDS/Protocols/ViewProtocol.swift +++ b/VDS/Protocols/ViewProtocol.swift @@ -9,13 +9,14 @@ import Foundation import UIKit import Combine +internal protocol DispatchQueueViewProtocol: AnyObject { + var updateWorkItem: DispatchWorkItem? { get set } +} + public protocol ViewProtocol: AnyObject, Initable, Resettable, Enabling, Surfaceable { /// Set of Subscribers for any Publishers for this Control. var subscribers: Set { get set } - /// Key of whether or not updateView() is called in setNeedsUpdate() - var shouldUpdateView: Bool { get set } - /// Executed on initialization for this View. func initialSetup() @@ -27,17 +28,28 @@ public protocol ViewProtocol: AnyObject, Initable, Resettable, Enabling, Surface /// Used to update any Accessibility properties. func updateAccessibility() + + /// Called when there are changes in a View based off a change events or from local properties. + func setNeedsUpdate() } extension ViewProtocol { - /// Called when there are changes in a View based off a change events or from local properties. + private func doUpdate() { + updateView() + updateAccessibility() + } + public func setNeedsUpdate() { - if shouldUpdateView { - shouldUpdateView = false - updateView() - updateAccessibility() - shouldUpdateView = true + guard let dispatchQueueSelf = self as? DispatchQueueViewProtocol else { + doUpdate() + return } + dispatchQueueSelf.updateWorkItem?.cancel() + let workItem = DispatchWorkItem { [weak self] in + self?.doUpdate() + } + DispatchQueue.main.async(execute: workItem) + dispatchQueueSelf.updateWorkItem = workItem } }