// // ViewProtocol.swift // VDS // // Created by Matt Bruce on 7/22/22. // 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 } /// Executed on initialization for this View. func initialSetup() /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. func setup() /// Used to make changes to the View based off a change events or from local properties. func updateView() /// 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 { private func doUpdate() { updateView() updateAccessibility() } public func setNeedsUpdate() { 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 } } extension ViewProtocol where Self: UIView { /// Helper method for removing a superview and updating Self. public func removeFromSuperview(_ view: UIView){ if view.superview != nil { view.removeFromSuperview() setNeedsDisplay() } } } extension ViewProtocol where Self: UIControl { /// Helper method to assign a completion block to a specific UIControl Event using Combine and stored in the subscribers. public func addEvent(event: UIControl.Event, block: @escaping (Self)->()) { publisher(for: event) .sink(receiveValue: { c in block(c) }).store(in: &subscribers) } }