Files
divkit/client/ios/DivKit/Variables/DivPropertiesStorage.swift
ansestepanov e3b7cf549f properties error handling
commit_hash:978f56b368a7a7703e6d2c83059dab292160b9cf
2025-08-27 18:02:15 +03:00

129 lines
3.0 KiB
Swift

import Foundation
import LayoutKit
import VGSL
final class DivPropertiesStorage {
struct ChangeEvent {
let changedProperties: Set<DivVariableName>
}
let initialPath: UIElementPath?
private let outerStorage: DivPropertiesStorage?
private var _values = DivProperties()
private let lock = AllocatedUnfairLock()
var allValues: DivProperties {
lock.withLock {
_allValues
}
}
var values: DivProperties {
lock.withLock {
_values
}
}
private var _allValues: DivProperties {
(outerStorage?.allValues ?? [:]) + _values
}
convenience init(
outerStorage: DivPropertiesStorage? = nil
) {
self.init(outerStorage: outerStorage, initialPath: nil)
}
init(
outerStorage: DivPropertiesStorage?,
initialPath: UIElementPath?
) {
self.outerStorage = outerStorage
self.initialPath = initialPath
}
func getPropertyValue(_ name: DivVariableName) -> DivProperty? {
let property = lock.withLock {
_values[name]
}
return property ?? outerStorage?.getPropertyValue(name)
}
func getVariableValue(_ name: DivVariableName) -> DivVariableValue? {
let variableValue = _values[name]?.toVariableValue()
return variableValue ?? outerStorage?.getVariableValue(name)
}
/// Gets property value.
/// If property with the given name not exists gets value from the outer storage.
func getValue<T>(_ name: DivVariableName) -> T? {
let property = lock.withLock {
_values[name]
}
if let property {
return property.typedValue()
}
return outerStorage?.getValue(name)
}
/// Replaces all properties with new ones in single transaction.
/// Does not affect outer storage.
func replaceAll(
_ properties: DivProperties
) {
lock.withLock {
_values = properties
}
}
func update(
path: UIElementPath,
name: DivVariableName,
newValue: DivVariableValue?
) -> Bool {
guard let property = (lock.withLock { _values[name] }),
let newValue else {
return false
}
guard let actionHandler = property.actionHandler else {
DivKitLogger.error("Action Handler is not set in propertiesStorage")
return false
}
guard !property.actions.isEmpty else {
DivKitLogger
.error(
"Cannot set property. No setters provided. Name: '\(name.rawValue)'"
)
return true
}
for action in property.actions {
actionHandler.handle(
action,
path: path,
source: .property,
localValues: [property.newValueVariableName: newValue.hashableValue],
sender: nil
)
}
return true
}
}
extension DivVariableValue {
fileprivate var hashableValue: AnyHashable {
switch self {
case let .string(value): value
case let .number(value): value
case let .integer(value): value
case let .bool(value): value
case let .color(value): value
case let .url(value): value
case let .dict(value): value
case let .array(value): value
}
}
}