iOS 界面跳转路由化解耦 runtime

1,307 阅读3分钟

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];
}

本文的所有参数输入都是以字典行书进行传输,其他类型大同小异,就不一一演示,感兴趣的同学到Github查看