作者:漢斯哈哈哈 授權本站轉載。
在開發項目中,會有這樣變態的需求:
推送:根據服務端推送過來的數據規則,跳轉到對應的控制器
feeds列表:不同類似的cell,可能跳轉不同的控制器(噓!產品經理是這樣要求:我也不確定會跳轉哪個界面哦,可能是這個又可能是那個,能給我做靈活嗎?根據後台返回規則任意跳轉?)
思考:wocao!這變態的需求,要拒絕他嗎?
switch判斷呗,考慮所有跳轉的因素?這不得寫死我...
switch () { case : break; default: break; }
我是這麼個實現的(runtime是個好東西)
利用runtime動態生成對象、屬性、方法這特性,我們可以先跟服務端商量好,定義跳轉規則,比如要跳轉到A控制器,需要傳屬性id、type,那麼服務端返回字典給我,裡面有控制器名,兩個屬性名跟屬性值,客戶端就可以根據控制器名生成對象,再用kvc給對象賦值,這樣就搞定了 ---O(∩_∩)O哈哈哈
比如:根據推送規則跳轉對應界面HSFeedsViewController
HSFeedsViewController.h:
進入該界面需要傳的屬性
@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; }
具體使用和代碼: https://github.com/HHuiHao/Universal-Jump-ViewController