在开发项目中,会有这样变态的需求:服务器
推送:根据服务端推送过来的数据规则,跳转到对应的控制器app
feeds列表:不一样相似的cell,可能跳转不一样的控制器(嘘!产品经理是这样要求:我也不肯定会跳转哪一个界面哦,多是这个又多是那个,能给我作灵活吗?根据后台返回规则任意跳转?)atom
思考:wocao!这变态的需求,要拒绝他吗?spa
switch判断呗,考虑全部跳转的因素?这不得写死我...code
switch () { case : break; default: break; }
我是这么个实现的(runtime是个好东西)orm
利用runtime动态生成对象、属性、方法这特性,咱们能够先跟服务端商量好,定义跳转规则,好比要跳转到A控制器,须要传属性id、type,那么服务端返回字典给我,里面有控制器名,两个属性名跟属性值,客户端就能够根据控制器名生成对象,再用kvc给对象赋值,这样就搞定了 ---O(∩_∩)O哈哈哈对象
好比:根据推送规则跳转对应界面HSFeedsViewController开发
HSFeedsViewController.h:字符串
进入该界面须要传的属性get
@interface HSFeedsViewController : UIViewController // 注:根据下面的两个属性,能够从服务器获取对应的频道列表数据 /** 频道ID */ @property (nonatomic, copy) NSString *ID; /** 频道type */ @property (nonatomic, copy) NSString *type; @end
AppDelegate.m:
推送过来的消息规则
// 这个规则确定事先跟服务端沟通好,跳转对应的界面须要对应的参数 NSDictionary *userInfo = @{ @"class": @"HSFeedsViewController", @"property": @{ @"ID": @"123", @"type": @"12" } };
接收推送消息
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { [self push:userInfo]; }
跳转界面
- (void)push:(NSDictionary *)params { // 类名 NSString *class =[NSString stringWithFormat:@"%@", params[@"class"]]; const char *className = [class cStringUsingEncoding:NSASCIIStringEncoding]; // 从一个字串返回一个类 Class newClass = objc_getClass(className); if (!newClass) { // 建立一个类 Class superClass = [NSObject class]; newClass = objc_allocateClassPair(superClass, className, 0); // 注册你建立的这个类 objc_registerClassPair(newClass); } // 建立对象 id instance = [[newClass alloc] init]; // 对该对象赋值属性 NSDictionary * propertys = params[@"property"]; [propertys enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { // 检测这个对象是否存在该属性 if ([self checkIsExistPropertyWithInstance:instance verifyPropertyName:key]) { // 利用kvc赋值 [instance setValue:obj forKey:key]; } }]; // 获取导航控制器 UITabBarController *tabVC = (UITabBarController *)self.window.rootViewController; UINavigationController *pushClassStance = (UINavigationController *)tabVC.viewControllers[tabVC.selectedIndex]; // 跳转到对应的控制器 [pushClassStance pushViewController:instance animated:YES]; }
检测对象是否存在该属性
- (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; }