iOS 界面跳转路由化解耦 初探
- 语言:objective-c
- 库:runtime
本文章主要是为了解决在开发中,界面跳转,相互引入界面代码侵入严重,使用路由的思路进行解耦,欢迎指正。废话不说,下面进入正题。。。
实现步骤
- 使用 <objc/runtime.h> 中提供的 objc_getClass()方法,根据界面名称创建实例,获取即将前往的页面类
//根据字符串创建类 const char *class = [className cStringUsingEncoding:NSASCIIStringEncoding]; //根据类名获取类 Class toClass = objc_getClass(class); - 使用遍历查询跟控制器的自控制器 获取当前最上次界面
#pragma mark - 获取当前控制器 + (UIViewController *)topViewController { return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; } + (UIViewController *)topViewControllerWithRootViewController:(UIViewController *)rootViewController { if ([rootViewController isKindOfClass:[UITabBarController class]]) { UITabBarController *tabBarController = (UITabBarController *)rootViewController; return [self topViewControllerWithRootViewController:tabBarController.selectedViewController]; }else if ([rootViewController isKindOfClass:[UINavigationController class]]){ UINavigationController *nav = (UINavigationController *)rootViewController; return [self topViewControllerWithRootViewController:nav.visibleViewController]; }else if (rootViewController.presentedViewController){ UIViewController *presentedViewController = rootViewController.presentedViewController; return [self topViewControllerWithRootViewController:presentedViewController]; }else{ return rootViewController; } } - 使用当行控制器进行跳转界面
//创建对象(写到这里已经可以进行随机页面跳转了) id nextVC = [[toClass alloc] init]; //获取当前控制器进行跳转界面 [[self topViewController].navigationController pushViewController:nextVC animated:YES];
以上流程简单介绍了无参数输入界面跳转,下面是完整实现方法
/** 无参数跳转界面
* @param className 要push的界面类名
*/
+(void)pushToControll:(NSString *)className
{
//根据字符串创建类
const char *class = [className cStringUsingEncoding:NSASCIIStringEncoding];
//根据类名获取类
Class toClass = objc_getClass(class);
if (!toClass) {
#ifdef DEBUG
//传参数类不存在不做跳转,并弹出提示
UIAlertController *alert =[UIAlertController alertControllerWithTitle:@"提示" message:@"跳转的界面还未创建" preferredStyle:UIAlertControllerStyleAlert];
[[self topViewController] presentViewController:alert animated:YES completion:nil];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:nil];
});
return;
#else
return;
#endif
}
//创建对象(写到这里已经可以进行随机页面跳转了)
id nextVC = [[toClass alloc] init];
//获取当前控制器进行跳转界面
[[self topViewController].navigationController pushViewController:nextVC animated:YES];
}
界面跳转有无参数输入,也有带参数输入的,接下来就是带参数输入实现
创建跳转界面类,获取当前界面类都已经实现,参数如何传入下一个界面,接下来是重点。。。
由于runtime库中有提供获取类属性的方法,可以使用class_copyPropertyList 获取类的属性列表,然后使用setValue: forKey: 方法赋值,具体操作接着往下看
- 根据已生成的类获取类的属性列表
// instance 即将跳转界面类
unsigned int outCount, i;
// 获取对象里的属性列表
objc_property_t * properties = class_copyPropertyList([instance class], &outCount);
- 根据获取的属性列表遍历,生成属性字符串名称
for (i = 0; i < outCount; i++) {
objc_property_t property =properties[i];
// 属性名转成字符串
NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
free(properties);
}
- 判断输入参数名称是否存在属性列表中,如果存在就赋值,不存在报错提示
/**
* 检测对象是否存在该属性
*/
+ (BOOL)checkIsExistPropertyWithInstance:(id)instance verifyPropertyName:(NSString *)verifyPropertyName
{
unsigned int outCount, i;
// 获取对象里的属性列表
objc_property_t * properties = class_copyPropertyList([instance class], &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property =properties[i];
// 属性名转成字符串
NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
// 判断该属性是否存在
if ([propertyName isEqualToString:verifyPropertyName]) {
free(properties);
return YES;
}
}
free(properties);
return NO;
}
完整实现带参数界面跳转流程
/** 有参数跳转界面
* @param className 要push的界面类名
* @param dic 界面所需参数字典
*/
+(void)pushToControll:(NSString *)className withPropertyValueDic:(NSMutableDictionary *)dic
{
//根据字符串创建类
const char *class = [className cStringUsingEncoding:NSASCIIStringEncoding];
//根据类名获取类
Class toClass = objc_getClass(class);
if (!toClass) {
#ifdef DEBUG
//传参数类不存在不做跳转,并弹出提示
UIAlertController *alert =[UIAlertController alertControllerWithTitle:@"提示" message:@"跳转的界面还未创建" preferredStyle:UIAlertControllerStyleAlert];
[[self topViewController] presentViewController:alert animated:YES completion:nil];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:nil];
});
return;
#else
return;
#endif
}
//创建对象(写到这里已经可以进行随机页面跳转了)
id nextVC = [[toClass alloc] init];
//根据传进来的字典 ,跳转界面传参数赋值
[dic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([self checkIsExistPropertyWithInstance:nextVC verifyPropertyName:key]) {
//kvc给属性赋值
[nextVC setValue:obj forKey:key];
}else {
NSLog(@"这个类不包含key=%@的属性",key);
}
}];
//获取当前控制器进行跳转界面
[[self topViewController].navigationController pushViewController:nextVC animated:YES];
}