ios之“多代理”,“多繼承”,以及動(dòng)態(tài)調(diào)用類(lèi)方法實(shí)例方法

一、多代理,多繼承

對(duì)于Objective-C來(lái)說(shuō)是不支持多繼承的,由于消息機(jī)制名字查找發(fā)生在運(yùn)行時(shí)而非編譯時(shí),很難解決多個(gè)基類(lèi)可能導(dǎo)致的二義性問(wèn)題。
不過(guò)其實(shí) Objective-C 也無(wú)需支持多繼承,我們可以找到如下幾種間接實(shí)現(xiàn)多繼承目的的方法:

消息轉(zhuǎn)發(fā)
delegate和protocol
類(lèi)別

消息轉(zhuǎn)發(fā)

當(dāng)向某個(gè)Object發(fā)送某消息,但runtime system在當(dāng)前類(lèi)和父類(lèi)中都找不到對(duì)應(yīng)方法的實(shí)現(xiàn)時(shí),runtime system并不會(huì)立即報(bào)錯(cuò)使程序崩潰,而是依次執(zhí)行下列步驟


1.從圖中我們可以很明顯的看出,當(dāng)某個(gè)類(lèi)沒(méi)有實(shí)現(xiàn)某個(gè)方法的時(shí)候,會(huì)先向當(dāng)前類(lèi)發(fā)送resolveInstanceMethod信號(hào),檢查是否動(dòng)態(tài)向該類(lèi)添加了方法,如果未實(shí)現(xiàn),則轉(zhuǎn)而進(jìn)入快速轉(zhuǎn)發(fā)步驟;
2.向當(dāng)前類(lèi)發(fā)送forwardingTargetForSelector(快速轉(zhuǎn)發(fā))信號(hào),若該方法返回值對(duì)象非nil或非self,檢查返回的target是否實(shí)現(xiàn)了該方法,若實(shí)現(xiàn)了則調(diào)用這個(gè)方法,若為nil或者self,則會(huì)轉(zhuǎn)而進(jìn)行標(biāo)準(zhǔn)轉(zhuǎn)發(fā)步驟;
3.如果未實(shí)現(xiàn)快速轉(zhuǎn)發(fā),則會(huì)向當(dāng)前類(lèi)發(fā)送methodSignatureForSelector:消息獲取Selector對(duì)應(yīng)的方法簽名。返回值非空則通過(guò)forwardInvocation:轉(zhuǎn)發(fā)消息,返回值為空則向當(dāng)前對(duì)象發(fā)送doesNotRecognizeSelector:消息,程序崩潰退出(標(biāo)準(zhǔn)消息轉(zhuǎn)發(fā))

快速消息轉(zhuǎn)發(fā)示例

    //Teacher類(lèi)需要實(shí)現(xiàn)將消息轉(zhuǎn)發(fā)給Doctor:
   - (id)forwardingTargetForSelector:(SEL)aSelector
  {
      Doctor *doctor = [[Doctor alloc]init];
  if ([doctor respondsToSelector:aSelector]) {
    return doctor;
  }
  return nil;
 } 

標(biāo)準(zhǔn)消息轉(zhuǎn)發(fā)示例

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];
    if (signature==nil) {
        for (id target  in self.targets){
            signature = [target methodSignatureForSelector:aSelector];
        }
        
    }
//    NSUInteger argCount = [signature numberOfArguments];//
//    for (NSInteger i=0 ; i<argCount ; i++) {//
//    }//
    
    return signature;
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    SEL seletor = [anInvocation selector];
    for (id target in self.targets) {
        if ([target respondsToSelector:seletor]) {
            [anInvocation invokeWithTarget:target];
        }

    }
    
}

兩種消息轉(zhuǎn)發(fā)方式的比較

快速消息轉(zhuǎn)發(fā):簡(jiǎn)單、快速、但僅能轉(zhuǎn)發(fā)給一個(gè)對(duì)象
標(biāo)準(zhǔn)消息轉(zhuǎn)發(fā):稍復(fù)雜、較慢、但轉(zhuǎn)發(fā)操作實(shí)現(xiàn)可控,可以實(shí)現(xiàn)多對(duì)象轉(zhuǎn)發(fā)

在ios中的使用場(chǎng)景

場(chǎng)景一
場(chǎng)景一是取自開(kāi)發(fā)文檔的代碼示例,他其實(shí)是通過(guò)消息傳遞機(jī)制實(shí)現(xiàn)了多重繼承功能,使proxy擁有了NSSting與NSArray倆個(gè)類(lèi)的方法屬性
場(chǎng)景二
場(chǎng)景二是解決了NSTimer輪播功能的循環(huán)引用的問(wèn)題。

二、動(dòng)態(tài)調(diào)用類(lèi)方法以及實(shí)例方法

在做項(xiàng)目的代碼重構(gòu)時(shí),使用了mvvm模式與mvp模式相結(jié)合,然后就盡可能的抽取代碼,盡量減少相同的代碼,比如創(chuàng)建不同的cell,在我重建的項(xiàng)目中,所有plain類(lèi)型的列表都共用了一個(gè)基類(lèi)的tableviewcontroller,在子類(lèi)中完全看不見(jiàn)和tableview相關(guān)的代碼,然后在子類(lèi)中根據(jù)不同的cell,創(chuàng)建帶有不同identifier的cell!這個(gè)想法很快得到了實(shí)現(xiàn),但是在動(dòng)態(tài)創(chuàng)建cell的時(shí)候,卻遇到了一個(gè)大問(wèn)題,就是我無(wú)法根據(jù)(nsclassfromstring)生成的class來(lái)動(dòng)態(tài)調(diào)用創(chuàng)建cell的方法,后來(lái)就使用了先regisiter tableviewCell類(lèi)的方式!直至最近看了雷純鋒大神的mvvmreactcocoa以及afn中關(guān)于動(dòng)態(tài)調(diào)用的一些方法,才發(fā)現(xiàn)如此簡(jiǎn)單,這里我也總結(jié)一下,希望能對(duì)各位朋友有所幫助,也是對(duì)我自己的幾個(gè)總結(jié)與記憶

//創(chuàng)建cell
+ (id)cellWithTableView:(UITableView *)tableView identifier:(NSString *)identifier
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
        cell = [[self alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
    }
    return cell;
}


Class cls = NSClassFromString(@"TableViewCell");
//雖然xcode不會(huì)提示,但是可以這樣調(diào)用,為了安全在調(diào)用之前最好先cls instancerespondtoselector判斷以下,以預(yù)防由于方法不存在導(dǎo)致app崩潰
    TableViewCell *cell = [cls cellWithTableView:tableView  identifier:@"dasd"];
    TableViewCell *cell1 = [cls performSelector:@selector(cellWithTableView:identifier:) withObject:tableView withObject:@"ceshi"];
    NSLog(@"%@  ===== %@",cell, cell1);

三、instancesRespondToSelector與respondsToSelector的區(qū)別

- (void)objectFun
{
    NSLog(@"object function");
}

+ (void)classFun
{
    NSLog(@"class function");
}


BOOL flag;

flag = [Test1 instancesRespondToSelector:@selector(objectFun)]; //YES

flag = [Test1 instancesRespondToSelector:@selector(classFun)]; //NO

flag = [Test1 respondsToSelector:@selector(objectFun)]; //NO

flag = [Test1 respondsToSelector:@selector(classFun)]; //YES

Test1 *obj = [[Test1 alloc] init];

flag = [obj respondsToSelector:@selector(objectFun)]; //YES

flag = [obj respondsToSelector:@selector(classFun)]; //NO

總結(jié)

  1. instancesRespondToSelector只能寫(xiě)在類(lèi)名后面,respondsToSelector可以寫(xiě)在類(lèi)名和實(shí)例名后面。

  2. [類(lèi) instancesRespondToSelector]判斷的是該類(lèi)的實(shí)例是否包含某方法,等效于:[該類(lèi)的實(shí)例 respondsToSelector]。

  3. [類(lèi) respondsToSelector]用于判斷是否包含某個(gè)類(lèi)方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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