Cocoa Binding 實用教程

首先說這不是一個新技術,它很老,老到幾乎沒人提起它。

這是蘋果 MVC 模式下的產物,最早在沒有 iPhone 的時候就已經誕生了,它是用來配合 Xcode 圖形化設置界面用的——比如 NIB,當然,現在已經變成 XIB了,哦,還有 Storyboard。

現在如果說起要 bind 一個 Storyboard 中的對像到代碼中,你可能查到的都是這樣的:

在左側欄點擊鼠標右鍵打開小窗口,然後【拉線】連接代碼中的聲明與實際的 UIButton……

這樣在程序加載這個 Storyboard 時,你圖形化創建的 Button 就自動連接到了代碼的聲明中,比如:

沒錯,通常來說我們是這麼用的,但如果我這是一個“設置”界面,裡邊有大量的簡單控件,但要根據用戶當前設置狀態來改變和顯示(這是個很常見的情景,畢竟哪個 App 沒個偏好設置呢? ),大量的 @IB插座@IBAction為 可能並不是一個好的選擇,因為除了這些,你還需要在初始化代碼中增加大量的配置讀取代碼,狀態判斷,然後再去更改對應控件的狀態,如果選項多的話,那基本就是災難了。

就拿落格輸入法的設置界面來說,每一頁都有很多的按鈕控件

就拿落格輸入法的設置界面來說,每一頁都有很多的按鈕控件

Cocoa Binding 救你命

打開 Xcode ,加載一個 Xib,選中一個控件,在右側欄你會看到常見的屬性設置界面:

Xcode 中常見的屬性設置欄

Xcode 中常見的屬性設置欄

你可能經常使用前邊幾個功能:

通常 Xcode 中常用的功能選項

通常 Xcode 中常用的功能選項

但,這個功能你肯定沒用過:

Cocoa Binding 設置界面

Cocoa Binding 設置界面

如果你去網上查找,那幾乎得不到什麼有用的介紹——因為它很古老了。得益於 Objc 的 MVC 設計風格,實際上每一個控件都可以直接監聽你對像中的變量,並自動根據它的變化來改變自身顯示的,你完全不需要去初始化那個對象,也不用根據用戶當前的設置來設定這個按鈕是可用還是不可用,一切其實都可以是自動的,你需要提供的——不過是一個變量而已。

不過問題來了,現在已經都在用 Swift 了,怎麼才能讓它綁定到 Swift 代碼中的變量呢?如果你聲明一個變量,並用這個界面來進行綁定,那麼就會遇到運行時錯誤:

這是由於 Swift 默認不向 Objc 暴露變量名稱導致的,如果任何 #選擇() 調用方法一樣,我們在對應的變量前加上 @對象 動態 ,比如這樣 @對象 動態 mySetting = ,這樣,就可以綁定成功了。

注意,這裡我們除了常見的 @對象 外,還追加了 動態 修飾,如果只使用前者,則可能在第一次調用時失敗, Swift 依舊會將你聲明的變量優化成靜態,這樣 Cocoa Binding 就不能動態監聽我們的綁定了。

(取決於你的編譯優化,為了保證無論如何綁定都能生效,還是應該加上 動態 修飾)

在綁定界面,我們選中一個 Button,比如我這個按鈕控件是有選中狀態的那種 ☑️,所以它有開和關兩種狀態,於是我就可以把它的 進行綁定,這裡要記得先設置好 Xib 的 文件小號 所有者 一般這個默認是空的,設置好後,我們就可以選擇綁定到 文件小號 所有者 了:

綁定對象實例變量到 UI 界面

綁定對象實例變量到 UI 界面

這裡要使用 KeyPath 進行設置,實際上就是你變量的名字即可。現在這個按鈕的狀態就會自動根據變量的值進行改變了。完全不需要任何初始化設置。

額外的,除了按鈕對象,你還可以綁定 Label,顯然,它的 value 就是字符串對象了。值得一提的是,如果你綁定一個數組控件……比如 NSPopUpButton 這種,它實際上是有多個數據,那麼你也可以在這個設置界面的下方找到 selectedIndex 這樣的狀態進行綁定,值類型就是我們熟悉的 Int ,如果你直接綁定 value,那值其實是一個比較複雜的 NSArrayController。

當然,如你所見,你還可以方便地綁定一個空間的 Enabled, isHidden 等等狀態,但凡是能設置的狀態,幾乎都能和變量進行綁定,根據情況自動發生改變——再也不用繁瑣的代碼來操作界面了!

進階:值轉換器

設置綁定的時候,會有一個默認留空的選項, 值轉換器 ,它可以將你綁定的值進行一定的處理,比如默認的,將布爾值進行反轉,判斷空為 true 或者 ,除此之外,我們還可以自定義如何對值進行處理。

比如我的設置選項有 0 1 2 三個狀態,但按鈕選中與否是兩個,我需要將它映射到 0 和 2 上,默認的 Transformer 就無能為力了。

首先,我們要繼承一個 值轉換器 ,這樣就能自定義處理流程:

其中 轉化價值(_ : Any?)-> Any? 返回的是控件需要的值,比如我的按鈕,我就設置 返回 一個 == 2 這樣當且僅當值為 2 時按鈕狀態為啟用。

allowReverseTransformation() -> 布爾 規定了這個 值轉換器 是否能逆向轉換,默認是 ,這裡我需要逆向,因為按鈕選定時應該給變量設置為 2 而不是 1 ,所以我要使用 reverseTransformedValue(_ : Any?) -> Any? 來將按鈕控件傳入的值轉換成變量需要的值。

寫好後我們需要將這個自定義的 值轉換器 進行註冊,否則 Swift 是找不到這個對象的:

我們在任何初始化界面之前的地方註冊即可,注意我直接給它起名為 "ValueTransformer2" ,然後就可以在 Xcode 的 Binding 界面將 ValueTransformer 寫成這個 ValueTransformer2 了,這裡我故意將名稱寫的和類名稱一致,你也可以寫成其他不對應的名字。


額外地,如果你用了自己的配置管理實例,那麼也可以將綁定的變量寫為計算屬性,這是完全沒有問題的,不過值得一提的是,綁定變量的控件,是依靠監控對應變量的 didSet 來獲取通知的,這是唯一觸發界面更新的方式,所以,如果你使用了計算屬性,那麼更新了後台存儲後,記得也要觸發一下計算屬性的 didSet ,比如

 

本文由 落格博客 原創撰寫:落格博客 » Cocoa Binding 實用教程

轉載請保留出處和原文鏈接:https://www.logcg.com/archives/3456.html

關於作者

R0uter

如非聲明,本人所著文章均為原創手打,轉載請註明本頁面鏈接和我的名字。

發表評論

您的電子郵件地址不會被公開. 必填字段標 *