上一篇文章列出了共32道IOS面試題: http://www.cnblogs.com/fkdd/archive/2012/03/13/2394724.html
下面從第一題開始解答:
題目:1.Object-c的類可以多重繼承么?可以實現多個接口么?Category是什么?重寫一個類的方式用繼承好還是分類好?為什么?
關於多繼承:
首先 object-c不能夠多繼承,類似下面代碼的這種方式是絕對通不過編譯的.當然,你也可以把NSString前面的":"去掉再試試,呵呵!
那么有沒有別的方式來替代呢?有,一種我們稱之為偽繼承,另一種我們可以通過ios中無處不在的@protocol委托方式來實現.
1.偽繼承
盡管再objtive-C中不提供多繼承,但它提供了另外一種解決方案,使對象可以響應在其它類中實現的消息(別的語言中,一般叫方法,兩者無差別). 這種解決方案叫做消息轉發,它可以使一個類響應另外一個類中實現的消息。
在一般情況下,發送一個無法識別的消息會產生一個運行時的錯誤,導致應用程序崩潰,但是注意,在崩潰之前,iphone運行時對象為每個對象提供了第二次機會來處理消息。捕捉到一條消息后可以把它重定向到可以響應該消息的對象。
這個功能完全通過消息轉發來實現,發送消息給一個無法處理該選擇器的對象時,這個選擇器就會被轉發給 forwardInvocation 方法.接收這條消息的對象,用一個NSInvocation的實例保存原始的選擇器和被請求的參數.所以,我們可以覆蓋 forwardInvocation 方法,並把消息轉發給另外一個對象.
1.1 實現消息轉發功能
在給程序添加消息轉發功能以前,必須覆蓋兩個方法,即methodSignatureForSelector: 和 forwardInvocation:。methodSignatureForSelector:的作用在於為另一個類實現的消息創建一個有效的方法簽名。forwardInvocation:將選擇器轉發給一個真正實現了該消息的對象.
例子:
1.
1 - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
2 {
3 NSMethodSignature* signature = [super methodSignatureForSelector:selector];
4
5 if (!signature)
6 signature = [self.carInfo methodSignatureForSelector:selector];
7
8 return signature;
9 }
2.
1 - (void)forwardInvocation:(NSInvocation *)invocation
2 {
3 SEL selector = [invocation selector];
4
5 if ([self.carInfo respondsToSelector:selector])
6 {
7 [invocation invokeWithTarget:self.carInfo];
8 }
9 }
3.調用
1 Car *myCar = [Car car]; //Car為一個類
2 [(NSString *)myCar UTF8String] //這里調用NSString中的UTF8String方,注意Car中並未實現該方法
解釋: 這里借iphone開發秘籍的例子來說明, self.carInfo是一個只讀的NSString對象,存在於Car類中.例子中Car實例是無法正確的為另外一個對象(NSString)實現的選擇器創建一個有效的簽名。運行時當檢查到當前沒有有效的簽名,即進入該對象(這里是myCar)的methodSignatureForSelector:方法中,此時,將在這個方法中對每個偽繼承進行迭代並嘗試構建一個有效的方法簽名的機會.例如代碼中,當myCar調用UTF8String時,由於無法從當前對象中獲得消息,轉入第二次機會捕捉消息,首先進入methodSignatureForSelector:方法,采用迭代的方式為當前被調用的方法創建一個有效的簽名,得到簽名后,轉入forwardInvocation:方法對其調用的方法(UTF8String)進行實現. forwardInvocation:中,首先獲得調用的方法(UTF8String),判斷self.carInfo(一個nsstring對象)能否響應該方法,如果可以,將調用UTF8String對象的目標轉換為self.carInfo對象. 這樣 ,我們就實現了多繼承,呵呵!!
注:如果您仍有疑問,可訪問蘋果的官方文檔查詢消息轉發相關內容: 地址 http://www.apple.com.cn/developer/mac/library/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/chapter_6_section_1.html#//
apple_ref/doc/uid/TP40008048-CH105-SW1
2.委托
在IOS中委托通過一種@protocol的方式實現,所以又稱為協議.協議是多個類共享的一個方法列表,在協議中所列出的方法沒有響應的實現,由其它人來實現.這叫好比我想買個手機,所以我有個buyIphone 方法,但是我不知道誰那買手機,所以把這個需求發布出去(比如公布在網站上),如果有賣手機的商人(也就是說他能實現buyIphone這個方法)看到,他就會接受我的委托,(在商人自己的類中實現<XXXdelegate>),那么我的委托對象就指向了這個商人..當我要買手機的時候,直接找他就行了.
例如:
@protocol MyDelegate
-(void)buyIphone:(NSString *)iphoneType money:(NSString *)money;
@end
@interface My : NSObject
{
id<MyDelegate> deleage;
}
@property(assign,nonatomic)id<MyDelegate> delegate;
@end
代碼中聲明了一個協議 名叫Mydelegate,在其中有一個buyIphone方法,即一個委托項。當我要購買手機的時候只需要通過delegate 調用 BuyIphone方法即可.
如下:
-(void)willbuy
{
[delegate buyIphone:@"iphone 4s" money:@"4888"];
}
我不必關心誰現實了這一委托,只要實現了這個委托的類,並且buyIphone是聲明的委托中必須實現的方法,那么就一定能夠得到結果.
例如:商人類實現了這一委托(用<Mydelegate>表示實現)
#import <Foundation/Foundation.h>
#import "My.h"
@interface Business : NSObject<MyDelegate>
@end
然后在 @implementation Business 中調用 buyIphone方法
#import "Business.h"
@implementation Business
-(void)buyIphone:(NSString *)iphoneType money:(NSString *)money
{
NSLog(@"手機有貨,這個價錢賣你了,發貨中!!");
}
@end
就ok啦。這樣是不是也模擬了多繼承呢?通過委托,其實你也就擺脫了去考慮多繼承方面的事情,從而關注當前類。
汗,一道題才寫了一半,下一篇繼續。。。。手打字酸了!