runtime學(xué)習(xí)(六):runtime的實(shí)際應(yīng)用——萬能界面跳轉(zhuǎn)

注:本文不是原創(chuàng)斩萌,只是在學(xué)習(xí)中做的整理和筆記抹沪,以便自己以后更好的復(fù)習(xí)纵菌。原文來自runtime從入門到精通系列洋闽。

在開發(fā)過程中玄柠,可能有如下的需求:

  1. 在tableView類型的展示列表中,點(diǎn)擊每個cell中人物頭像都可以跳轉(zhuǎn)到人物詳情诫舅,可參見微博中的頭像羽利,同理包括轉(zhuǎn)發(fā)、評論按鈕刊懈、各種鏈接及l(fā)inkcard铐伴。
  2. 跳轉(zhuǎn)到任意頁面
    (1)產(chǎn)品要求,某個頁面的不同banner圖俏讹,點(diǎn)擊可以跳轉(zhuǎn)到任何一個頁面当宴,可能是原生的頁面A、頁面B泽疆,或者是web頁C户矢。
    (2)在web頁面,可以跳轉(zhuǎn)到任何一個原生頁面殉疼。
    (3)在遠(yuǎn)程推送中跳轉(zhuǎn)到任意指定的頁面梯浪。

以上2種需求,我想大多數(shù)開發(fā)者都遇到過瓢娜,并且可以實(shí)現(xiàn)這種功能挂洛。畢竟,這是比較基礎(chǔ)的功能眠砾。但是代碼未必那么優(yōu)雅虏劲。

一般處理辦法:

針對 1:一般初學(xué)者會用target或者block等方法在tableView的代理方法拿到事件,并把要執(zhí)行的跳轉(zhuǎn)寫到controller里褒颈。功能是可以實(shí)現(xiàn)的柒巫,但問題是這種cell及相似的cell(布局有些變化,或者多幾個少幾個控件)一般出現(xiàn)在多個頁面谷丸。這樣的話相同的代碼就會出現(xiàn)在多個地方堡掏。就算把跳轉(zhuǎn)方法抽取出來寫成category,但是target或者block總是每個地方都要寫的刨疼。

針對 2:初級的方法是每個地方寫一坨判斷及跳轉(zhuǎn)泉唁,高級一些是抽取出來寫在基類或者category鹅龄。

優(yōu)雅的解決辦法(利用runtime):

利用runtime動態(tài)生成對象、屬性亭畜、方法這特性扮休,我們可以先跟服務(wù)端商量好,定義跳轉(zhuǎn)規(guī)則贱案,比如要跳轉(zhuǎn)到A控制器肛炮,需要傳屬性id、type宝踪,那么服務(wù)端返回字典給我侨糟,里面有控制器名,兩個屬性名跟屬性值瘩燥,客戶端就可以根據(jù)控制器名生成對象秕重,再用kvc給對象賦值,這樣就搞定了厉膀。

舉例:比如根據(jù)推送規(guī)則跳轉(zhuǎn)對應(yīng)界面HSFeedsViewController

進(jìn)入該界面需要傳的兩個屬性:

// HSFeedsViewController.h

@interface HSFeedsViewController : UIViewController
// 注:根據(jù)下面的兩個屬性溶耘,可以從服務(wù)器獲取對應(yīng)的頻道列表數(shù)據(jù)
/** 頻道ID */
@property (nonatomic, copy) NSString *ID;
/** 頻道type */
@property (nonatomic, copy) NSString *type;

@end

服務(wù)端推送過來的消息規(guī)則:

// 這個規(guī)則肯定事先跟服務(wù)端溝通好,跳轉(zhuǎn)對應(yīng)的界面需要對應(yīng)的參數(shù)
NSDictionary *userInfo = @{
                           @"class": @"HSFeedsViewController",
                           @"property": @{
                                        @"ID": @"123",
                                        @"type": @"12"
                                   }
                           };

AppDelegate.m 中添加以下代碼片段:

接收推送消息
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    [self push:userInfo];
}

跳轉(zhuǎn)界面
- (void)push:(NSDictionary *)params
{
    // 類名
    NSString *class =[NSString stringWithFormat:@"%@", params[@"class"]];
    const char *className = [class cStringUsingEncoding:NSASCIIStringEncoding];
    // 從一個字串返回一個類
    Class newClass = objc_getClass(className);
    if (!newClass)
    {
        // 創(chuàng)建一個類
        Class superClass = [UIViewController class];
        newClass = objc_allocateClassPair(superClass, className, 0);
        // 注冊你創(chuàng)建的這個類
        objc_registerClassPair(newClass);
    }
    // 創(chuàng)建對象
    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];
        }
    }];
    // 獲取導(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
{
    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];
        //  屬性名轉(zhuǎn)成字符串
        NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
        // 判斷該屬性是否存在
        if ([propertyName isEqualToString:verifyPropertyName]) {
            free(properties);
            return YES;
        }
    }
    free(properties);
    return NO;
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末服鹅,一起剝皮案震驚了整個濱河市凳兵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌企软,老刑警劉巖庐扫,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異仗哨,居然都是意外死亡形庭,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門厌漂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萨醒,“玉大人,你說我怎么就攤上這事苇倡「恢剑” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵雏节,是天一觀的道長胜嗓。 經(jīng)常有香客問我,道長钩乍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任怔锌,我火速辦了婚禮寥粹,結(jié)果婚禮上变过,老公的妹妹穿的比我還像新娘。我一直安慰自己涝涤,他們只是感情好媚狰,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著阔拳,像睡著了一般崭孤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上糊肠,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天辨宠,我揣著相機(jī)與錄音,去河邊找鬼货裹。 笑死嗤形,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的弧圆。 我是一名探鬼主播赋兵,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼搔预!你這毒婦竟也來了霹期?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤拯田,失蹤者是張志新(化名)和其女友劉穎历造,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體勿锅,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡帕膜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了溢十。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垮刹。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖张弛,靈堂內(nèi)的尸體忽然破棺而出荒典,到底是詐尸還是另有隱情,我是刑警寧澤吞鸭,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布寺董,位于F島的核電站,受9級特大地震影響刻剥,放射性物質(zhì)發(fā)生泄漏遮咖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一造虏、第九天 我趴在偏房一處隱蔽的房頂上張望御吞。 院中可真熱鬧麦箍,春花似錦、人聲如沸陶珠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽揍诽。三九已至诀蓉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間暑脆,已是汗流浹背渠啤。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饵筑,地道東北人埃篓。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像根资,于是被迫代替她去往敵國和親架专。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容