[iOS][OC] 開發利器:控制器傳送門VCPicker(附demo)

0 背景

在項目早期開發階段,還不須要接入後臺網絡數據,主要工做的界面的開發。 隨着業務頁面的深刻,要查看二級、三級頁面的效果就須要編譯後跳轉兩三次甚至更多,不斷地重複這個過程相對來講,就沒有能夠直接啓動就查看那個頁面來得那麼高效。git

1 解決方案

1.1 簡單粗暴的方式

常見的作法是在application:didFinishLaunchWithOptions:時直接push到想要到達的頁面,以下:github

 //  獲取到能夠展現的容器控制器
UINavigationViewController *naviVC = [self getNavigationVC];
// 建立想要跳轉的控制器
TargetViewController *targetVC = [[TargetViewController alloc] init]; 
// 跳轉到目標頁面
[naviVC pushViewController:targetVC animated:YES]; 
複製代碼

這樣能夠在程序啓動時便捷地跳轉了,但在多個工程師協同合做時有一個潛在的問題objective-c

  • 是會污染其餘同事的代碼
  • 而多個同事都寫了這樣的便捷頁面跳轉而不當心提交到公共代碼庫就會出代碼衝突

1.2 傳送門方案VCPicker

爲了方便每一個協同開發的工程師跳轉任意頁面,一個更效率的方式有一個入口能夠隨時找到某一個ViewController頁面的類,跳轉過去便可,順着這個思路須要作兩個事情:安全

  • 找到工程裏全部的ViewController控制器類
  • 設置一個統一的入口

實現的途徑:bash

  • 利用objc-runtime機制獲取項目中全部的類,再篩選出全部UIViewController的子類,以字符串的形式保存類名,以列表的形式展示,當點擊某一個類時,經過類初始化一個實例便可實現目標頁面的跳轉
Class *classes = NULL;
    int numClasses = objc_getClassList(NULL, 0);
複製代碼
  • 傳送門入口的設計,最初是想經過搖一搖來實現從而不影響原有UI的效果,可是不便於模擬器上的使用,因此借鑑了蘋果的輔助手勢Assist touch懸浮球設計,在程序的keyWindow上懸浮一個能夠挪動的小球從而在編譯進入程序後能夠第一時間點擊查看控制器列表選擇想要跳轉的控制器。
// 建立懸浮效果
[[UIDynamicAnimator alloc] initWithReferenceView:self.superview];
複製代碼

2 優化

在使用的過程當中逐步衍生並優化了一些有用的功能網絡

2.1 使用class-prefix

因爲經過runtime獲取到的類有不少是系統的私有類,甚至不響應NSObject協議的,在操做這些類時則會很是危險,此外一些UI的控制器類(好比圖片選擇、通信錄獲取)是須要權限才能訪問和建立實例的,而咱們實際的項目中通常都有類前綴class-prefix(外包的同窗不服....),經過類前綴能夠快速地篩選出實際項目中的業務頁面app

2.2 展現方式

根據具體的業務場景基本上分爲帶導航和不帶導航兩種,所以使用presentViewController的方法,一種會建立導航控制器後present,另外一種則是直接present;學習

2.3 獲取title

有的小夥伴提出,看到的是茫茫的一片類名而不知道業務title不方便同事之間學習,經過分析大部分都會在viewDidLoad方法設置title,或者navigationItem.title或者tabbarItem.title,所以須要實例化一個控制器對象,嘗試調用viewDidLoad方法,實踐證實如此是不安全的,一方面是viewDidLoad是控制器的生命週期方法原則上是父類調用的,再者不少同窗還在viewDidLoad進行了KVO和通知的監聽的監聽,手動調用viewDidLoad會致使重複監聽的問題,而調用[controller view]方法則能夠完美地解決這個問題,調用[controller view]方法會在內部依次觸發[controller loadView]和[controller viewDidLoad]方法,以後就能獲取到想要的title信息;此外,在實例化對象調用view屬性觸發viewDidLoad時可能由於初始化參數不足的問題拋出異常,所以須要在此處代碼塊進行@try-catch保護,並保存異常信息提醒當前頁面存在潛在異常。優化

// 建立實例,獲取title
            UIViewController *controller = nil;
            NSMutableDictionary *dic = [NSMutableDictionary dictionary];
            
            @try {
                if (_needTitle) {
                    controller = [[NSClassFromString(className) alloc] init]; // nil
                    [controller view]; // to active viewDidLoad so we can get conroller.title
                }
                
            } @catch (NSException *exception) {
                NSLog(@"[VCPicker <%@> exception: %@]", className, exception);
                dic[kErrorKey] = exception.description;
                
            } @finally {
                dic[kNameKey] = className;
                dic[kTitleKey] = controller.title ?: (controller.navigationItem.title ?: (controller.tabBarItem.title ?: className));
                [self refreshHistoryForControllerInfo:dic];
                [array addObject:dic];
            }
複製代碼

2.4 增長曆史記錄和搜索功能

從衆多的類列表中,通過排序能夠方便查找,更方便的方法是提供搜索功能,下次再進入時若是保存了歷史記錄就更好了,因此這些都要有,因此都有了spa

感謝開發過程當中Zoro和Ace同窗的極好的建議

在實際開發項目中進行應用,內部實現使用DEBUG宏進行預編譯的判斷,確保上線時不會出問題,使用VCPicker不用移除也能夠正常審覈上線App store。

3 源代碼和demo

demo

相關文章
相關標籤/搜索