我目前正在爲iOS重寫表單控制器。這是一個綁定到模型的自定義對象,並處理編輯表單字段,跳到上一個/下一個字段,處理自定義鍵盤,驗證數據...雙向KVO:控制器更新模型,它通知控制器
第一個版本基於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
和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; DR
ControllerA
是Model
註冊KVO觀察者。
ControllerB
更新Model
==>ControllerA
收到KVO通知。沒關係。
ControllerA
更新Model
==>ControllerA
收到KVO通知。我不想要這個。
剛剛聽到KVO通知,你剛剛做出了什麼改變?我認爲這種選擇比刪除並重新添加自己作爲KVO觀察員更「不適合並且有潛在危害」。 – occulus 2013-02-14 16:02:06
我不想執行'textField.text = @「something」;'當我在更新模型之前做的最後一件事情是'textField.text = @「something」;'。想象一下,這是一個更經濟的用戶界面更新(重新繪製大型控件,圖像處理...),經常發生(離散控制,如滑塊)。 – Cyrille 2013-02-14 16:03:29
如果您確定接收通知是有效的冪等操作,則多次接收相同的通知無關緊要。 – occulus 2013-02-14 16:03:59