前言
已經(jīng)很久沒有寫文章了,前面寫過一篇 關(guān)于 UIWindow 的文章,在文章的最后提過懸浮球。用 UIWindow 來做懸浮球,可以懸浮在任意頁面,基于這個(gè)特性,我將其做成了一個(gè)工具,用在我們的項(xiàng)目開發(fā)中,今天把它作為主角來講一講。
先上代碼 → ZYSuspensionView GitHub 傳送門
為什么會(huì)有它
想要指定執(zhí)行一些代碼
在做公司項(xiàng)目的時(shí)候,可能會(huì)有這樣的情況,我需要在第一個(gè)進(jìn)某個(gè)頁面的時(shí)候彈出一些東西,簡(jiǎn)單做法,可能就會(huì)再、在 NSUserDefaults 中記錄一個(gè)值,表明彈出過??赡芪业谝淮螐棾鲋笥忠恍﹩栴},我改了代碼,運(yùn)行工程,重新進(jìn)頁面讓它彈出,可是卻彈不出來了,因?yàn)橐呀?jīng)標(biāo)記為彈出過,把包刪了,重運(yùn)行工程即可。

不過有了懸浮球,我通過點(diǎn)擊懸浮球,彈出一個(gè)列表,列表中每個(gè) cell 對(duì)應(yīng)我預(yù)先寫好的一些常用代碼,例如清除 NSUserDefaults 所有鍵值對(duì)等等,然后就達(dá)到了想要的效果。當(dāng)然這個(gè)比喻有很多槽點(diǎn),不過就這樣吧,不糾結(jié)。
真實(shí)用例如下,希望對(duì)你有點(diǎn)啟發(fā):
-
通過手動(dòng)插入一條的指定體重體脂率的體重?cái)?shù)據(jù)
我們公司做體脂秤,所以開發(fā)的時(shí)候經(jīng)常需要這么做,不然就得光著腳在秤上稱,還不一定是自己想要的數(shù)值
清除 NSUserDefaults,讓包里的標(biāo)記干凈得像初戀一樣
-
顯示 log
有時(shí)候測(cè)試人員測(cè)試的時(shí)候,發(fā)現(xiàn)頁面的 bug,可能我們?cè)谟行?case 預(yù)留了一些 log,但是想要導(dǎo)出就麻煩一些,通過點(diǎn)懸浮球列表的某個(gè) cell 跳轉(zhuǎn)到一個(gè)顯示 log 的頁面,快捷方便
-
顯示當(dāng)前賬號(hào)的 user id 及其他信息
我們需要經(jīng)常查當(dāng)前賬號(hào)信息
-
跳轉(zhuǎn)到指定頁面
正在開發(fā)某個(gè)頁面,需要依賴工程里的東西,所以在工程里開發(fā),但是還沒有開發(fā)完,由于入口深,每次改了一些東西重新跑工程還得點(diǎn)幾下,麻煩。修改 app 首頁的某個(gè)按鈕點(diǎn)擊事件,直接點(diǎn)擊進(jìn)入也不合適,影響正式代碼,而且容易忘記改回來。
其他一些雜七雜八的...
不想每次都輸入賬號(hào)密碼
因?yàn)轫?xiàng)目的原因,很多功能展示都和當(dāng)前賬號(hào)的數(shù)據(jù)有關(guān)系,所以想要自測(cè)自己的功能是否 OK,就需要頻繁切換賬號(hào),以保證每種情況都是真實(shí) cover 到了。

用懸浮球,彈出一個(gè)賬號(hào)菜單,點(diǎn)擊自己想要登陸的賬號(hào),直接自動(dòng)登陸,媽媽再也不用擔(dān)心我每天都要輸入幾百次密碼了。 ???
好用嗎?怎么用?
個(gè)人感覺還是很好用了,為自己開發(fā)省去了不少時(shí)間,同時(shí)也為測(cè)試同學(xué)省去不少麻煩(有點(diǎn)自賣自夸的性質(zhì)了哈 ??)。頁面簡(jiǎn)單樸素,就是懸浮球 + 一個(gè)列表,咱不整那些虛的,主要就是實(shí)用。好不好用,試試就知道了。
我已經(jīng)將這個(gè)懸浮球做成了一個(gè) Pod 庫,公司的項(xiàng)目用了近一年了,穩(wěn)定,暫未發(fā)現(xiàn)有什么問題,如有 bug 可以給我提 issue。
這個(gè)組件主要分為個(gè)部分
- SuspensionView
- TestManager
- LoginManager
SuspensionView 就是單純一個(gè)懸浮球,可以單獨(dú)集成。
TestManager
TestManager 是一個(gè)單例,將你預(yù)先寫好的代碼塊保存好,然后通過點(diǎn)擊懸浮列表的某個(gè) cell 執(zhí)行相應(yīng)代碼塊。
使用的時(shí)候,一般分為兩個(gè)部分:
一些是常駐的一些測(cè)試代碼,例如展示 log,清除 user defaults 等...
NSArray *baseArray = @[
@{
kTestTitleKey: @"clean user defaults",
kTestAutoCloseKey: @YES,
kTestActionKey: ^{
NSLog(@"click 'clean user defaults'");
[self cleanUserDefaults];
}
},
@{
kTestTitleKey:@"something",
kTestAutoCloseKey: @NO,
kTestActionKey:^{
NSLog(@"click 'something'");
}
},
];
[ZYTestManager setupPermanentTestItemArray:baseArray];
-
kTestTitleKey是測(cè)試條目的名字 -
kTestAutoCloseKey為點(diǎn)擊該條目之后是否自動(dòng)關(guān)閉懸浮列表 -
kTestActionKey很顯然,這就是點(diǎn)擊之后想要執(zhí)行的代碼
當(dāng)然,一些不常用的測(cè)試代碼,可能就是你突發(fā)奇想要跳轉(zhuǎn)到某個(gè)頁面,但是不影響項(xiàng)目的其他功能正常運(yùn)行,就可以使用另一個(gè)方法
[ZYTestManager addTestItemWithTitle:@"new item" autoClose:YES action:^{
// click new item : do something ~~~~~~~~~~
}];
這里需要說明一些,傳入 block 的時(shí)候,如果用到 self,最好使用 __weak,避免影響到你正常功能,畢竟 TestManager 是一個(gè)單例。
LoginManager
LoginManager 顧名思義,就是拿來做自動(dòng)登錄的,同樣,點(diǎn)擊 login 懸浮球,彈出賬號(hào)列表,再點(diǎn)擊對(duì)于 cell,LoginManager 會(huì)回調(diào)給你儲(chǔ)存好的這個(gè)賬號(hào)的賬號(hào)和密碼。
- (void)loginManager:(ZYLoginManager *)loginManager loginWithAccout:(NSString *)account password:(NSString *)password
{
// 這里去實(shí)現(xiàn)你的自動(dòng)登錄
}
可能你會(huì)說,自動(dòng)登錄都是我實(shí)現(xiàn)了,拿你還有什么用呢。LoginManager 做了如下事情:
- 幫你存儲(chǔ)賬號(hào)密碼
- 列表展示你預(yù)先設(shè)置或者登錄過的賬號(hào),并通過你的點(diǎn)擊回調(diào)給你
自動(dòng)登錄的代碼是不可能幫你做好的,因?yàn)槊總€(gè)工程里的與登錄對(duì)于的代碼完全不同,不可能通用,所以,咱只能做到這一步了,哈哈哈。不過這里還是給你提供了一個(gè)獲取當(dāng)前控制器的方法,可以直接使用
UIViewController *currentVC = [ZYLoginManager currentViewControllerWithWindow:nil];
其實(shí)自動(dòng)登錄無非就是兩步
- 獲取當(dāng)前控制器,查看是否為登錄的控制器
- 如果是,利用
performSelector調(diào)用登錄部分的代碼
如果不是登錄的控制器怎么辦呢?一般的 app,在沒有登錄的時(shí)候一般第一個(gè)頁面就是登錄頁面,或者點(diǎn)擊一下某個(gè)按鈕,跳轉(zhuǎn)到登錄頁面,其實(shí)獲取當(dāng)前控制器的時(shí)候,完全可以判斷是否為第一個(gè)頁面,如果是,就 performSelector 跳轉(zhuǎn)到登錄頁面,再在登錄頁面 performSelector 調(diào)用登錄部分的代碼。根據(jù)不同情況再做一些調(diào)整吧。
除了是實(shí)現(xiàn)這個(gè)方法,你還需要做兩件事情:
- 告訴我你登錄成功了,并且告訴我是哪個(gè)賬號(hào),我這時(shí)候需要隱藏登錄的懸浮球,并且為你保存賬號(hào)
[[NSNotificationCenter defaultCenter] postNotificationName:@"kZYLoginSuccessNotificationKey"
object:@{account:password}];
- 告訴我你退出登錄了,我需要重新展示登錄按鈕,方便下一次自動(dòng)登錄
[[NSNotificationCenter defaultCenter] postNotificationName:@"kZYLogoutSuccessNotificationKey"
object:nil];
安全嗎?
這東西,能跟著上線嗎,不小心蹦出來個(gè)懸浮球給用戶看到那不是尷尬了。不能攜帶上線的話,每次上線還得刪除,多麻煩啊。?? 這個(gè)大可放心,我已經(jīng)帶著它上線了 n 個(gè)版本了,而且?guī)缀跛写a我都加上了
#if DEBUG
...
#endif
所以根本不需要擔(dān)心,只要工程改為 release 模式運(yùn)行壓根就出現(xiàn)不了懸浮球,里面的代碼根本也不會(huì)執(zhí)行。
我的建議是像我 demo 里面那樣,寫一個(gè) config 類,將上面所有常用的測(cè)試代碼和測(cè)試賬號(hào)都寫在這里類里面,放在一起,將污染做到最小。如果你這樣做了,在這里 config 類的 setup 方法再加上一個(gè) #if DEBUG,你會(huì)發(fā)現(xiàn) TestManager 和 LoginManager 這兩個(gè)單例對(duì)象根本就不會(huì)初始化,還有什么可擔(dān)心的。
基本就這么多吧,如果你覺得有用的話,請(qǐng)不要吝嗇你的 star?? 哦!