在你的開發(fā)過程中,是否遇到過如下的需求:
在tableView類型的展示列表中,點擊每個cell中人物頭像都可以跳轉(zhuǎn)到人物詳情,可參見微博中的頭像,同理包括轉(zhuǎn)發(fā)、評論按鈕、各種鏈接及l(fā)inkcard。
跳轉(zhuǎn)到任意頁面
(1)產(chǎn)品要求,某個頁面的不同banner圖,點擊可以跳轉(zhuǎn)到任何一個頁面,可能是原生的頁面A、頁面B,或者是web頁C。
(2)在web頁面,可以跳轉(zhuǎn)到任何一個原生頁面。
(3)在遠程推送中跳轉(zhuǎn)到任意指定的頁面。
以上2種需求,我想大多數(shù)開發(fā)者都遇到過,并且可以實現(xiàn)這種功能。畢竟,這是比較基礎(chǔ)的功能。但是代碼未必那么優(yōu)雅。
針對 1:一般初學(xué)者會用target或者block等方法在tableView的代理方法拿到事件,并把要執(zhí)行的跳轉(zhuǎn)寫到controller里。功能是可以實現(xiàn)的,但問題是這種cell及相似的cell(布局有些變化,或者多幾個少幾個控件)一般出現(xiàn)在多個頁面。這樣的話相同的代碼就會出現(xiàn)在多個地方。就算把跳轉(zhuǎn)方法抽取出來寫成category,但是target或者block總是每個地方都要寫的。
針對 2:初級的方法是每個地方寫一坨判斷及跳轉(zhuǎn),高級一些是抽取出來寫在基類或者category。
利用runtime動態(tài)生成對象、屬性、方法這特性,我們可以先跟服務(wù)端商量好,定義跳轉(zhuǎn)規(guī)則,比如要跳轉(zhuǎn)到A控制器,需要傳屬性id、type,那么服務(wù)端返回字典給我,里面有控制器名,兩個屬性名跟屬性值,客戶端就可以根據(jù)控制器名生成對象,再用kvc給對象賦值,這樣就搞定了。
舉例:比如根據(jù)推送規(guī)則跳轉(zhuǎn)對應(yīng)界面HSFeedsViewController
進入該界面需要傳的屬性:

AppDelegate.m 中添加以下代碼片段:
推送過來的消息規(guī)則
// 這個規(guī)則肯定事先跟服務(wù)端溝通好,跳轉(zhuǎn)對應(yīng)的界面需要對應(yīng)的參數(shù)NSDictionary*userInfo = @{
@"class": @"HSFeedsViewController",
@"property": @{
@"ID": @"123",
@"type": @"12"}
};
接收推送消息
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{
? ? ?[selfpush:userInfo];
}
跳轉(zhuǎn)界面:
- (void)push:(NSDictionary*)params
{// 類名NSString*class =[NSStringstringWithFormat:@"%@", params[@"class"]];constchar*className = [class cStringUsingEncoding:NSASCIIStringEncoding];// 從一個字串返回一個類Class newClass = objc_getClass(className);if(!newClass)
{// 創(chuàng)建一個類Class superClass = [NSObjectclass];
newClass = objc_allocateClassPair(superClass, className,0);// 注冊你創(chuàng)建的這個類objc_registerClassPair(newClass);
}// 創(chuàng)建對象idinstance = [[newClass alloc] init];// 對該對象賦值屬性NSDictionary* propertys = params[@"property"];
[propertys enumerateKeysAndObjectsUsingBlock:^(idkey,idobj,BOOL*stop) {// 檢測這個對象是否存在該屬性if([selfcheckIsExistPropertyWithInstance:instance verifyPropertyName:key]) {// 利用kvc賦值[instance setValue:obj forKey:key];
}
}];// 獲取導(dǎo)航控制器UITabBarController*tabVC = (UITabBarController*)self.window.rootViewController;UINavigationController*pushClassStance = (UINavigationController*)tabVC.viewControllers[tabVC.selectedIndex];// 跳轉(zhuǎn)到對應(yīng)的控制器[pushClassStance pushViewController:instance animated:YES];
}
檢測對象是否存在該屬性:
- (BOOL)checkIsExistPropertyWithInstance:(id)instance verifyPropertyName:(NSString*)verifyPropertyName
{unsignedintoutCount, i;// 獲取對象里的屬性列表objc_property_t * properties = class_copyPropertyList([instance
class], &outCount);for(i =0; i < outCount; i++) {
objc_property_t property =properties[i];//? 屬性名轉(zhuǎn)成字符串NSString*propertyName = [[NSStringalloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];// 判斷該屬性是否存在if([propertyName isEqualToString:verifyPropertyName]) {
free(properties);returnYES;
}
}
free(properties);returnNO;
}
具體使用和代碼::https://github.com/HHuiHao/Universal-Jump-ViewController