動態更新
? ? 1、控件到 window 的層級關系:
? ? 2、分析控件的詳細路徑:
? ? 3、動態修改控件:
? ? 4、工具篇:
視圖的層級關系:
? ? 每個 App , 至少有一個根 Window , 通常情況下我們只用一個 。window 有一個 rootViewController , 這就是我們所謂的根視圖 , 我們所有的控制器都是放在 rootViewController 里面的。
如果在項目里有了這么一個路徑 , 我們可以做什么呢?
? ? * 在當項目很復雜 , 可以其它地方可以直接修改這個控件的狀態
? ? * 當某個控件命名存在卻又沒有顯示出來 , 可以通過路徑來輔助查找
? ? * 由服務器下發一些配置 , 使用 Runtime 去動態的修改已上線的項目
下面將介紹如何使用代碼來找出這些視圖(控件)的路徑
分析控件的詳細路徑
1、找出根 Window :
每一個視圖、控件 , 他們最終的根都是main函數返回的 application , 通過 [UIApplication sharedApplication] 可以得到 。 application 的 windows 屬性是一個數組 , 這里面裝的是這個應用的所有 Window , 我們通常用的是第一個也就是 application.windows[0]
2、遍歷視圖 :
得到了 window 對象一切都好辦了 。 然后拿到 window 的 rootViewController , 在獲取 rootViewController 里面所有的 childViewControllers 和 view 里的 subviews , 一直遞歸下去就可以得到當前屏幕里所有視圖對象了 , 同時可以通過 runtime 把它們的 property 、 delegate 都獲取出來 。
結合 Reveal 或者 Xcode 自帶的 Captuer View Hiearachy , 我們可以推測一下這兩個的的實現原理了 :
? ? 1、根據應用得到根視圖
? ? 2、遞歸獲取里面的所有控件
? ? 3、按照他們的層級關系一層一層的畫出來
動態修改控件
1、把上面獲取到的所有控件的詳細信息上傳到服務器 。
2、根據業務需求由服務器給我們下發對應的配置列表 , 以 button 為例 : 配置列表里必須要有 :
? ? 1)、button 的全路徑 : 如 UIWindow -> UIWindow -> UIView -> UIView -> ? ? ?UILayoutContainerView -> UITabBar -> UIView —> UIButton
? ? 2)、button 的唯一標識 : 如 tag 值或自己實現的一套算法生成的唯一標識 , 目的是防止與 button 同一層次的視圖搞混 。
? ? 3)、 根據路徑及唯一標識來匹配 App 里的控件 , 匹配和上面的查找原理是相通的。
? ? 4)、 匹配成功代表 button 確實存在 , 根據業務需求做后續操作 。
提示: 匹配策略盡可能的多 , 防止意外情況某一兩個標識生成失敗或者生成相同 。
3、修改 button 的狀態。
? ? 1)、 如某個按鈕點了會 Crash 或暫時不需要被點擊 , 但是又要展示出來 , 可以直接修改 button 的 enabled 屬性 。
? ? 2)、 如某業務暫時關閉 , 可以直接修改入口 按鈕 frame為0 , 前提是要自動布局已做好 。
? ? 3)、 如給購買 按鈕 添加監聽事件 addTarget: action: forControlEvents:
target 也可以通過上面 遍歷視圖 獲取到 , action 可以由服務器下發 , 也可以一開始就寫死 , 等有需求的時候直接傳不同的參數就行了 。
4、 綁定查找控件時 , 這個界面必須要已經初始化完成了才行 , 假如界面還沒生成肯定是查找不到這個控件的 。 這里給大家提供兩種思路 :
? ? 1、使用Runtime Method Swizzing , 直接把修改控件的方法與 didMoveToSuperview 和 didMoveToWindow 動態綁定 , 等這個控件加載出來之后再去修改 , 查找路徑正確的話肯定就能找到了 。
? ? 2、在具體的類里面 , 等控件的初始化方法調用完后 , 再去執行動態修改 , 如在viewDidLoad 里面初始化控件 , 在 viewWillAppear: 里面動態修改 。
建議使用第一種適用范圍更強 。
上架后的 應用 可能會遇到的一些突發狀況 , 未測出的Crash、臨時改點小需求 , 等等 , 我們總不能每次因為一點小改動就重新提交一次 App Store , 先不說 App Store 的審核時間 , 頻繁的讓用戶去更新應用 , 用戶也會煩的 。使用這篇文章所講的來實現動態更新是再合適不過了 。
首先上面講的 動態更新 是完全脫離出來的一個模塊 , 跟業務邏輯沒有任何關系 , 只需要部署一次就行了 , 等開發下一個項目也可以直接拿過去使用 。這里的動態更新適用于局部的視圖、控件的修改 , 如果你有其它需求可以考慮 JSPatch 、wax , 下發腳本也是一個不錯的選擇 。
工具篇:
使用一些UI調試的輔助工具 , 使我們查看視圖在項目中得層次結構更為方便 。
常用的UI調試的工具:
Captuer View Hiearachy
Reveal
Xcode自帶的 Captuer View Hiearachy 實現步驟:
? ? 1、打開Xcode , 運行項目 , 選擇最頂部的 Debug
? ? 2、Debug -> View Debugging -> Show View Frames
? ? 3、Debug -> View Debugging -> Captuer View Hiearachy
Xcode里面就變成了三維的視圖了 , Xcode左側展示出來的是層級關系的樹狀圖 。
Reveal的功能相對來說更強大 , 適用于UI調試視圖查找 。使用方法請看 Reveal集成指南 。