在開發項目中,會有這樣變態的需求:服務器
推送:根據服務端推送過來的數據規則,跳轉到對應的控制器app
feeds列表:不一樣相似的cell,可能跳轉不一樣的控制器(噓!產品經理是這樣要求:我也不肯定會跳轉哪一個界面哦,多是這個又多是那個,能給我作靈活嗎?根據後臺返回規則任意跳轉?)atom
思考:wocao!這變態的需求,要拒絕他嗎?orm
switch判斷唄,考慮全部跳轉的因素?這不得寫死我...對象
switch () { case : break; default: break; }
我是這麼個實現的(runtime是個好東西)開發
利用runtime動態生成對象、屬性、方法這特性,咱們能夠先跟服務端商量好,定義跳轉規則,好比要跳轉到A控制器,須要傳屬性id、type,那麼服務端返回字典給我,裏面有控制器名,兩個屬性名跟屬性值,客戶端就能夠根據控制器名生成對象,再用kvc給對象賦值,這樣就搞定了 ---O(∩_∩)O哈哈哈字符串
好比:根據推送規則跳轉對應界面HSFeedsViewControllerget
HSFeedsViewController.h:string
進入該界面須要傳的屬性產品
@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; }