Mac Cocoa 綁定 (Binding) 實作測試

前言

會研究綁定,主要是因為在研究 NSOutlineView (樹狀圖) 時,得知資料有二種處理方法,一種是由程式處理,一種是設定綁定,因為綁定的部份看不懂,所以才先研究簡單的綁定功能。

在網路上找到了這篇文章,看起來寫的蠻清楚的,例子也簡單好懂,不過實作時,偏偏無法運作,花了一晚找不到原因,也查不到相關資料,最後總算在某一篇問答中找到一句話,突破了盲點,才完成初步的綁定測試。

我的環境是:

macOS 10.15 Catalina

Xcode 11.1

Swift 5

也許之前的版本就沒有問題,這點我無法確定,底下一一說明操作經過。

基本設定

我就抄襲該篇的實作,先設計一個 Person 類別,繼承 NSObject,類別中有一個 scroe 屬性。並在 ViewController 中宣告 son 物件。

我原本以為是不是 scroe 不能宣告變數的類型?後來我有指定是 Int 也沒有問題,是我多慮了。

Storyboard 則放二個元件,一個 Slider 和一個輸入欄位。

綁定

  1. 選取 Slider

  2. 選取 Bindings Inspector

  3. 選取 Value

  4. 勾選 Bind to ,選擇 View Controller

  5. 選取 Model key Path,填入 son.score

同樣,輸入欄位也是同樣的綁定。

失敗的測試

就如一開始所說的,測試起來就是一片黑,完全沒有畫面,有如下的錯誤訊息。

這個過程卡了很久,Google 不少資料,但許多都是複雜的技術文章,寫的說明落落長,不然就是介紹 KVC、KVO、MVVM...等我還沒搞懂的一堆術語,愈看是頭愈大。

成功的測試

最後是 google 到一篇問答,有一個人提出一個關鍵詞 @objc,經過我各種測試之後,總算有了初步的成果。

於是我把程式改成如下,Person 類別中的 score 要加上 @objc,宣告 son 也要加上 @objc,這二個地方都要加,缺一不可。

再次執行果然就可以順利同步了。

【後記】後來又看有這種用法:

@objcMembers class Person: NSObject {

    var score = 0

}

大概是表示內部屬性不用一一加 @objc 了。

 

文中有提到,在拉動 Slider 時,輸入欄位並不會立刻更新,而是等到 Slider 拉到定位,輸入欄位才會更新。如果要即時更新,可將 Slider 的 Continuous 屬性勾選即可。

文中也提到,Swift 中預設是關閉了 KVO 的屬性監聽,只要在 score 屬性前面添加一個關鍵字 dynamic 就可以開啟了。

經實際測試,若沒有加 dynamic,雖然將 son.score 設定初值,呈現時也沒有反應出來。

如下圖,雖然有設定 son.score = 10,一開始的畫面依然是 0。

我增加一個按鈕,按下去會將 son.scroe 設定為 50,但實測結果並不會影響畫面的元件。我經由 Debug 去看,son.score 的確有更新,程式並沒有錯誤。

後來把 dynamic 加入之後,初值與執行時去改變 son.score,畫面的元件果然都能順利同步了。

下圖是加上 synamic 的宣告,執行時初值就是 10 了。

增加的按鈕,按下去 Slider 和輸入欄位也都立刻變成 50。

額外的測試

我有試著把 Person 類別的 NSObject 繼承移除,結果在 son 前面加上 @objc 就會出錯,因此若要使用物件來綁定,NSObject 還是要繼承才行。

後來在我 ViewController 加了一個變數

@objc synamic var xyz = 0

我發現元件與此變數一樣可以綁定,綁定時就把 son.score 換成 xyz 即可。因此似乎也不一定要使用繼續 NSObject 的物件來綁定。細節我還不清楚,這只是實際測試結果。

除了數據,不少屬性也都可以綁定,例如我也把 Hidden 與 Enabled 綁定,結果當綁定數據為 0 時,元件就會消失或 Disabled,符合我們的預期。

綁定 NSUserDefaultsController

還有一種綁定 User Defaults Controller 的方法,使用起來比上面更簡單,程式都不用寫,可以直接綁定元件的各種屬性。

以底下為例,先選擇 Slider,將它的 Value 綁定 User Defaults Controller,Controller Key 選 values,Model Key Path 隨意命名,我用 abc,感覺就是把 Slider 的值與 abc 這個變數綁定。

同樣,輸入欄位把 Value 綁定到 abc。

底下是把 Button 的 Font Size 綁定到 abc。

執行時,拉動 Slider,果然除了輸入欄位的數字會同步變更,Button 的文字大小也同時跟著改變。

這個方式還有個特別的地方,就是當程式關閉後,再次開啟時,Slider 的位置與輸入欄位數字依然保持不變,似乎這個 abc 變數會記錄在某個地方,程式再次開啟時會保持在上次結束的狀態,不用自己寫程式去記錄,算是蠻不錯的特性。

 
重要度:
文章分類:

發表新回應

借我放一下廣告