Вам не нужны наблюдатели для того, что вы описываете.Вам просто нужно немного памяти для вашего штата.Поскольку вы знаете, что это NSObject, вы можете сделать это с помощью среды выполнения ObjC.
// Since we know it's a UIView, we can use the ObjC runtime to store stuff on it
private var expandedProperty = 0
// In Xcode 10b1, you can make Expandable require this, but it's probably
// nicer to still allow non-UIViews to conform.
extension Expandable where Self: UIView {
// We'll need a primitive form to prevent infinite loops. It'd be nice to make this private, but
// then it's not possible to access it in custom versions of expand()
var _isExpanded: Bool {
get {
// If it's not know, default to expanded
return objc_getAssociatedObject(self, &expandedProperty) as? Bool ?? true
}
set {
objc_setAssociatedObject(self, &expandedProperty, newValue, .OBJC_ASSOCIATION_ASSIGN)
}
}
var isExpanded: Bool {
get {
return _isExpanded
}
set {
_isExpanded = newValue
if newValue { expand() } else { collapse() }
}
}
func expand() {
_isExpanded = true // Bypassing the infinite loop
print("expand")
}
func collapse() {
_isExpanded = false
print("collapse")
}
}
Если вы не знали, что это NSObject, вы можете получить то же самое с глобальным (частным)словарь, который отображает ObjectIdentifier -> Bool.Это просто утечка небольшого количества памяти (~ 16 байт на каждый просмотр, который вы свернули).
Тем не менее, я бы так не поступил.Наличие двух способов сделать одно и то же делает все намного сложнее.Я бы либо просто установил isExpanded
, либо установил бы isExpanded
только для чтения, а expand
и collapse
.Тогда вам не нужны дополнительные _isExpanded
.