我目前正在为 iOS 重写一个表单控制器。它是一个绑定到模型的自定义对象,并处理编辑表单字段、跳转到上一个/下一个字段、处理自定义键盘、验证数据......
第一个版本基于用于存储表单值的 plist,表单控制器本身保存所有数据。现在我想将存储(模型)与表单控制器分离,因此我已经决定使用 KVO。
为简单起见,让我们假设我有一个设计用于编辑缺勤时间跨度的表单。所以它有两个字段:leaveDate
和returnDate
.
我的模型如下:
@interface Absence
@property (strong, nonatomic) NSDate *leaveDate;
@property (strong, nonatomic) NSDate *returnDate;
@property (readonly, nonatomic) BOOL isValid;
@end
我的表单控制器有一个model
指向该对象的属性。
当用户点击我的 XIB 中的“离开日期”文本字段时,表单控制器会根据我的模型的当前值提交并显示一个日期选择器leaveDate
。当用户选择其他日期时,表单控制器使用setValue:forKey:
.
该isValid
属性被声明为受leaveDate
and returnDate
(使用+keyPathsForValuesAffectingIsValid
)影响,并且表单控制器已注册以监视此属性的更改,以动态启用/禁用提交按钮。
到目前为止,一切都像一个魅力。现在,对于扭曲的部分:
我希望我的表单控制器能够在模型打开时处理模型中的更改。示例:我在模型中有一条规则,即“缺勤必须至少持续 3 天”。当用户更改休假日期时,如果总时长不超过 3 天,则自动调整返回日期。
所以我的表单控制器还必须注册以监听所有属性的变化。问题是它既改变了属性,又监听了变化。
这样,当用户更改时leaveTime
,表单控制器会使用setValue:forKey:
更新模型,但会立即收到 KVO 通知,告知其刚刚所做的更改。这是不必要的并且可能有害(我只是自己进行了更改,不需要告诉我我刚刚完成了)。
到目前为止,我发现的唯一方法是在设置新值之前取消注册,然后立即重新注册,如下所示:
[self.model removeObserver:self forKeyPath:self.currentField.key];
[self.model setValue:newValue forKey:self.currentField.key];
[self.model addObserver:self forKeyPath:self.currentField.key options:NSKeyValueObservingOptionNew context:nil];
它正在工作,但它很丑陋,而且在性能方面我怀疑它是否很棒。
有人对如何做得更好有解释吗?
TL;博士
ControllerA
是 的注册 KVO 观察员Model
。
ControllerB
更新Model
==>ControllerA
收到 KVO 通知。没关系。
ControllerA
更新Model
==>ControllerA
收到 KVO 通知。我不要这个。