在開發專案中,會有這樣變態的需求:
推送:根據服務端推送過來的資料規則,跳轉到對應的控制器
feeds列表:不同類似的cell,可能跳轉不同的控制器(噓!產品經理是這樣要求:我也不確定會跳轉哪個介面哦,可能是這個又可能是那個,能給我做靈活嗎?根據後臺返回規則任意跳轉?)
思考:wocao!這變態的需求,要拒絕他嗎?
switch判斷唄,考慮所有跳轉的因素?這不得寫死我...
1 2 3 4 5 6 |
switch () { case : break; default: break; } |
我是這麼個實現的(runtime是個好東西)
利用runtime動態生成物件、屬性、方法這特性,我們可以先跟服務端商量好,定義跳轉規則,比如要跳轉到A控制器,需要傳屬性id、type,那麼服務端返回字典給我,裡面有控制器名,兩個屬性名跟屬性值,客戶端就可以根據控制器名生成物件,再用kvc給物件賦值,這樣就搞定了 ---O(∩_∩)O哈哈哈
比如:根據推送規則跳轉對應介面HSFeedsViewController
HSFeedsViewController.h
:
進入該介面需要傳的屬性
1 2 3 4 5 6 7 8 9 10 11 |
@interface HSFeedsViewController : UIViewController // 注:根據下面的兩個屬性,可以從伺服器獲取對應的頻道列表資料 /** 頻道ID */ @property (nonatomic, copy) NSString *ID; /** 頻道type */ @property (nonatomic, copy) NSString *type; @end |
AppDelegate.m
:
推送過來的訊息規則
1 2 3 4 5 6 7 8 |
// 這個規則肯定事先跟服務端溝通好,跳轉對應的介面需要對應的引數 NSDictionary *userInfo = @{ @"class": @"HSFeedsViewController", @"property": @{ @"ID": @"123", @"type": @"12" } }; |
接收推送訊息
1 2 3 4 |
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { [self push:userInfo]; } |
跳轉介面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
- (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]; } |
檢測物件是否存在該屬性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
- (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