在開發項目中,會有這樣變態的需求:
推送:根據服務端推送過來的數據規則,跳轉到對應的控制器
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