為什么可以重名?
在分析這兩個的區(qū)別之前,我們先思考一個問題溺蕉,為啥這兩個長一樣的東西不會發(fā)生命名沖突呢?
因?yàn)樵?OC 中郊酒,類和協(xié)議是存在于不同命名空間的,所以一個作為類,一個作為協(xié)議,他們是可以重名的语稠。
OC 中的基類
NSObject是基類,它再也沒有超類弄砍。但是 OC 不像 Java 只有一個基類,OC 有多個基類输涕,除了 NSObject 之外音婶,還含有一個 NSProxy 基類和其他各種各樣的基類。
NSObject 協(xié)議
擁有多個基類之后莱坎,也就引出了 NSObject 協(xié)議存在的理由衣式,NSObject 協(xié)議規(guī)定了一些所有基類都需要實(shí)現(xiàn)的基本方法和屬性,比如isEqual: 檐什、isKindOfClass碴卧、respondsToSelector等,當(dāng)然還有內(nèi)存管理的方法 retain 乃正、release住册、autorelease、retainCount等瓮具,這樣就定義了一個相對統(tǒng)一的接口和 OC 對象都可以響應(yīng)的方法荧飞。
我們可以看到這兩個基類都遵從 NSObject 協(xié)議。
@interface NSProxy <NSObject>
@interface NSObject <NSObject>
NSProxy 基類
NSObject 基類除了遵從 NSObject 協(xié)議之外名党,還實(shí)現(xiàn)了一大堆別的方法叹阔,有時候,我們自定義的類并不需要這些方法传睹。
比如我們自定義一些類耳幢,目的是進(jìn)行一些消息轉(zhuǎn)發(fā),這個時候我們就可以讓他繼承自 NSProxy 基類欧啤,代表一些代理睛藻、轉(zhuǎn)發(fā)作用的類,避免繼承自 NSObject 引入大量不需要的方法邢隧。
我們可以看到 NSProxy 有這兩個方法可以幫助實(shí)現(xiàn)消息轉(zhuǎn)發(fā):
- (void)forwardInvocation:(NSInvocation *)invocation;
- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel NS_SWIFT_UNAVAILABLE("NSInvocation and related APIs not available");
現(xiàn)在讓我們來嘗試一下修档,首先定義一個類繼承自 NSProxy,定義一個 object 屬性,并且實(shí)現(xiàn)上面所說的兩個方法:
@property (nonatomic,strong)NSObject *object;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
NSMethodSignature *methodSignature;
if (self.object) {
methodSignature = [self.object methodSignatureForSelector:sel];
}else{
methodSignature = [super methodSignatureForSelector:sel];
}
return methodSignature;
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
if (self.object) {
[invocation setTarget:self.object];
[invocation invoke];
}
}
關(guān)于 NSInvocation 函數(shù)的調(diào)用可以參考小的之前寫的這篇博文府框。
然后定義一個吃瓜群眾類……將 Proxy 類收到的方法調(diào)用都傳給他吱窝。
#import "Dog.h"
@implementation Dog
- (void)eat
{
NSLog(@"我是??讥邻,我想來點(diǎn)狗糧");
}
@end
實(shí)例化 Proxy 和 Dog,并且給 Proxy 傳一個eat調(diào)用院峡,可以看到兴使,這個消息最終傳給了 Dog:
ZNProxy *proxy = [ZNProxy alloc];
Dog *dog = [[Dog alloc] init];
//設(shè)置proxy的object為dog,以后proxy收到的消息最終都會傳給dog
proxy.object = dog;
[proxy performSelector:@selector(eat)];