一、多代理,多繼承
對(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é)
instancesRespondToSelector只能寫(xiě)在類(lèi)名后面,respondsToSelector可以寫(xiě)在類(lèi)名和實(shí)例名后面。
[類(lèi) instancesRespondToSelector]判斷的是該類(lèi)的實(shí)例是否包含某方法,等效于:[該類(lèi)的實(shí)例 respondsToSelector]。
[類(lèi) respondsToSelector]用于判斷是否包含某個(gè)類(lèi)方法。