iOS开发攻城狮的集散地iOS底层技术

解耦:Runtime优化页面跳转不需要引入头文件

2018-04-23  本文已影响32人  wg刚

通常由一个controller跳转到下一页面做法是:

#import "ViewController.h"
#import "WGOneViewController.h"

从ViewController跳转到WGOneViewController

    WGOneViewController *con = [[WGOneViewController alloc] init];
    [self.navigationController pushViewController:con animated:YES];

当然项目前期这么做也没有什么不对,但是会存在一个问题:当项目越来越大或者从ViewController跳转的下一页面越来越多的时候,就需要导入很多的头文件,造成多个页面的相互依赖,在项目后期需要组件化或者特定需求的时候就会造成很大困难。
这里给出一种不需要导入头文件的方案,这是demo
总体思路我根据代码详细给出:

  1. 新建一个页面的管理类,在里面统一管理需要跳转的类名称,即:每一个类名对应一个唯一ID,例如@”1-2“。这个id可以根据项目自己定义,我这里@"1-2"中1代表tabbar的索引,2代表在这个索引下的一个。
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface WGControllerId : NSObject

//单例
+ (WGControllerId *)WGControllerIdShare;
//根据页面id获取类名
- (NSString *)getControolerName:(NSString *)pageId;
//进行页面跳转的接口,fromCon是从哪个页面开始跳,toPageId是将要跳转到的页面id,isHas代表是否需要传值 ,param是需要传的值
- (void)pushFromController:(UIViewController *)fromCon toPageId:(NSString *)pageId hasParam:(BOOL)isHas param:(NSDictionary *)param;
@end
/*
 页面跳转的类统一在这里管理,key唯一,例如@"1-2"中1可代表tabbar中第1个
 */
- (NSString *)getControolerName:(NSString *)pageId{
    NSDictionary *pageDic = @{@"1-1":@"WGOneViewController",
                              @"1-2":@"WGTwoViewController",
                              @"1-3":@"WGThreeViewController"
        
    };
    return [pageDic valueForKey:pageId];
}
  1. 页面管理类负责跳转接口实现:
这里在属性传值的时候我自己定义了一个传值规则:在param这个字典中每一个key是需要属性传值的属性名,例如WGTwoViewController.h中有一个titleStr属性需要传值,那么我的传值字典内容为@{@"titleStr":@"这是需要传的值"}
这么做的目的就是在真正跳转的方法里,我只需要根据字典中的key就可以通过Runtime来生成对应属性的set方法,通过msg_send来把值传给下一页。

当然如果有更好的方法,也麻烦告诉我,非常感谢😊😊

- (void)pushFromController:(UIViewController *)fromCon toPageId:(NSString *)pageId hasParam:(BOOL)isHas param:(NSDictionary *)param{
    //根据定义好的pageId,拿到类名字符串
    NSString *className = [self getControolerName:pageId];
    //根据类名转化为Class类型
    Class classCon = NSClassFromString(className);
    //初始化并分配内存
    id toCon = [[classCon alloc] init];
    
    if (isHas) {
        //需要属性传值,则通过运行时来解决
        NSArray *keyArr = [param allKeys];
        for (int i = 0; i<keyArr.count; i++) {
            NSString *key = [keyArr objectAtIndex:i];
            id value = [param valueForKey:key];
            //把key的首字母大写
            NSString *firstStr = [key substringWithRange:NSMakeRange(0, 1)].uppercaseString;
            NSString *restStr = [key substringFromIndex:1];
            //生成对应属性的set方法
            NSString *selName = [NSString stringWithFormat:@"set%@%@:", firstStr, restStr];
            SEL method = NSSelectorFromString(selName);
            if ([toCon respondsToSelector:method]) {
                //等价于controller.shuxing = value;
                objc_msgSend(toCon, method, value);
            }
        }
    }
    [fromCon.navigationController pushViewController:toCon animated:YES];
}
  1. 在我的demo中进行页面跳转ViewController类里
switch (row) {
            case 0:{
                [[WGControllerId WGControllerIdShare] pushFromController:self toPageId:self.dataArr[row] hasParam:NO param:nil];
                break;
            }
            case 1:{
                [[WGControllerId WGControllerIdShare] pushFromController:self toPageId:self.dataArr[row] hasParam:YES param:@{@"titleStr":@"标题是传过来的"}];
                break;
            }
            case 2:{
                [[WGControllerId WGControllerIdShare] pushFromController:self toPageId:self.dataArr[row] hasParam:YES param:@{@"name":@"名字叫wg", @"age":@18}];
                break;
            }
#import "ViewController.h"
#import "WGControllerId.h"

这样我就不需要在ViewController里引入头文件了。如果对runtime不是很熟悉或者对生成属性的set方法那里不太明白的话可看我的这篇文章

上一篇 下一篇

猜你喜欢

热点阅读