在项目早期开发阶段,还不须要接入后台网络数据,主要工做的界面的开发。 随着业务页面的深刻,要查看二级、三级页面的效果就须要编译后跳转两三次甚至更多,不断地重复这个过程相对来讲,就没有能够直接启动就查看那个页面来得那么高效。git
常见的作法是在application:didFinishLaunchWithOptions:时直接push到想要到达的页面,以下:github
// 获取到能够展现的容器控制器
UINavigationViewController *naviVC = [self getNavigationVC];
// 建立想要跳转的控制器
TargetViewController *targetVC = [[TargetViewController alloc] init];
// 跳转到目标页面
[naviVC pushViewController:targetVC animated:YES];
复制代码
这样能够在程序启动时便捷地跳转了,但在多个工程师协同合做时有一个潜在的问题objective-c
为了方便每一个协同开发的工程师跳转任意页面,一个更效率的方式有一个入口能够随时找到某一个ViewController页面的类,跳转过去便可,顺着这个思路须要作两个事情:安全
实现的途径:bash
objc-runtime
机制获取项目中全部的类,再筛选出全部UIViewController的子类,以字符串的形式保存类名,以列表的形式展示,当点击某一个类时,经过类初始化一个实例便可实现目标页面的跳转Class *classes = NULL;
int numClasses = objc_getClassList(NULL, 0);
复制代码
Assist touch
悬浮球设计,在程序的keyWindow上悬浮一个能够挪动的小球从而在编译进入程序后能够第一时间点击查看控制器列表选择想要跳转的控制器。// 建立悬浮效果
[[UIDynamicAnimator alloc] initWithReferenceView:self.superview];
复制代码
在使用的过程当中逐步衍生并优化了一些有用的功能网络
因为经过runtime获取到的类有不少是系统的私有类,甚至不响应NSObject协议的,在操做这些类时则会很是危险,此外一些UI的控制器类(好比图片选择、通信录获取)是须要权限才能访问和建立实例的,而咱们实际的项目中通常都有类前缀class-prefix
(外包的同窗不服....),经过类前缀能够快速地筛选出实际项目中的业务页面app
根据具体的业务场景基本上分为带导航和不带导航两种,所以使用presentViewController的方法,一种会建立导航控制器后present,另外一种则是直接present;学习
有的小伙伴提出,看到的是茫茫的一片类名而不知道业务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];
}
复制代码
从众多的类列表中,通过排序能够方便查找,更方便的方法是提供搜索功能,下次再进入时若是保存了历史记录就更好了,因此这些都要有,因此都有了spa
在实际开发项目中进行应用,内部实现使用DEBUG
宏进行预编译的判断,确保上线时不会出问题,使用VCPicker不用移除也能够正常审核上线App store。