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