平時(shí)開發(fā)中我們使用的大部分類的基類都是NSObject,今天介紹另一個(gè)基類——NSProxy。
先來看一下蘋果官方文檔:
NSProxy
An abstract superclass defining an API for objects that act as stand-ins for other objects or for objects that don’t exist yet.
好的轩褐,我們知道了他是一個(gè)抽象類。
再往下
Overview
Typically, a message to a proxy is forwarded to the real object or causes the proxy to load (or transform itself into) the real object. Subclasses of NSProxy
can be used to implement transparent distributed messaging (for example, NSDistantObject
) or for lazy instantiation of objects that are expensive to create.
NSProxy
implements the basic methods required of a root class, including those defined in the NSObject
protocol. However, as an abstract class it doesn’t provide an initialization method, and it raises an exception upon receiving any message it doesn’t respond to. A concrete subclass must therefore provide an initialization or creation method and override the forwardInvocation:
and methodSignatureForSelector:
methods to handle messages that it doesn’t implement itself. A subclass’s implementation of forwardInvocation:
should do whatever is needed to process the invocation, such as forwarding the invocation over the network or loading the real object and passing it the invocation. methodSignatureForSelector:
is required to provide argument type information for a given message; a subclass’s implementation should be able to determine the argument types for the messages it needs to forward and should construct an NSMethodSignature
object accordingly. See the NSDistantObject
, NSInvocation
, and NSMethodSignature
class specifications for more information.
原來朋其,它的作用是一個(gè)映射括授,通過定義子類,并重寫
- (void)forwardInvocation:(NSInvocation *)anInvocation;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel;
這兩個(gè)方法來實(shí)現(xiàn)將消息轉(zhuǎn)發(fā)給真正的對象踏拜。我們知道OC不支持多繼承碎赢,通過NSProxy,就可以模擬實(shí)現(xiàn)多繼承速梗。那么現(xiàn)在肮塞,NSProxy怎么用呢?
假設(shè)現(xiàn)在有這樣一個(gè)需求:
我們已經(jīng)將項(xiàng)目中的網(wǎng)絡(luò)接口進(jìn)行了模塊化姻锁,將不同模塊下的接口放在了不同的文件中枕赵。當(dāng)我們想調(diào)用不同模塊下的接口時(shí),想要通過一個(gè)統(tǒng)一的映射來調(diào)用屋摔,現(xiàn)在我們來寫這個(gè)映射烁设。
首先,我們來創(chuàng)建兩個(gè)接口模塊钓试。
商品模塊:
@protocol ProductServiceProtocel <NSObject>
- (void)getProductInfo:(NSString *)productSkn;
@end
@interface ProductService : NSObject
@end
以及訂單模塊:
@protocol OrderServiceProtocel <NSObject>
- (void)submitOrder:(NSString *)prodcutName;
@end
@interface OrderService : NSObject
@end
注意:這里的接口聲明要寫在protocol中,然后讓我們的proxy遵循這兩個(gè)協(xié)議副瀑,用來騙過編譯器弓熏。
然后我們實(shí)現(xiàn)這兩個(gè)接口模塊:
@implementation ProductService
- (void)getProductInfo:(NSString *)productSkn {
NSLog(@"我是一件程序員標(biāo)配的橫條紋T,我的skn是%@",productSkn);
}
@end
@implementation OrderService
- (void)submitOrder:(NSString *)prodcutName {
NSLog(@"我買了一件%@",prodcutName);
}
@end
現(xiàn)在我們來寫我們的映射糠睡。
#import <Foundation/Foundation.h>
#import "ProductService.h"
#import "OrderService.h"
@interface ServiceProxy : NSProxy <ProductServiceProtocel, OrderServiceProtocel>
+ (ServiceProxy *)shareProxy;
@end
NSProxy是一個(gè)抽象類挽鞠,系統(tǒng)不提供init方法,所以需要我們自己實(shí)現(xiàn)。
#import "ServiceProxy.h"
#import <objc/runtime.h>
@implementation ServiceProxy
{
ProductService *_product;
OrderService *_order;
NSMutableDictionary *_targetProxy;
}
#pragma class method
+ (ServiceProxy *)shareProxy {
return [[ServiceProxy alloc] init];
}
#pragma init
- (ServiceProxy *)init {
_targetProxy = [NSMutableDictionary dictionary];
_product = [[ProductService alloc] init];
_order = [[OrderService alloc] init];
[self _registerMethodsWithTarget:_product];
[self _registerMethodsWithTarget:_order];
return self;
}
在init方法中信认,初始化成員變量已經(jīng)將各接口模塊中的方法以及對象映射在一個(gè)字典中材义。
#pragma private
- (void)_registerMethodsWithTarget:(id)target {
unsigned int methodsNum = 0;
Method *methodList = class_copyMethodList([target class], &methodsNum);
for (int i = 0; i < methodsNum; i++) {
Method method = methodList[i];
SEL temp_sel = method_getName(method);
const char *temp_method_name = sel_getName(temp_sel);
[_targetProxy setObject:target forKey:[NSString stringWithUTF8String:temp_method_name]];
}
free(methodList);
}
接下來就可以重寫系統(tǒng)提供的兩個(gè)方法,根據(jù)方法名從我們的映射字典中找到對應(yīng)的target嫁赏,然后執(zhí)行其掂。
#pragma override
- (void)forwardInvocation:(NSInvocation *)invocation {
SEL selector = invocation.selector;
NSString *methodName = NSStringFromSelector(selector);
id target = _targetProxy[methodName];
if (target && [target respondsToSelector:selector]) {
[invocation invokeWithTarget:target];
}else {
[super forwardInvocation:invocation];
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
NSString *methodName = NSStringFromSelector(sel);
id target = _targetProxy[methodName];
if (target && [target respondsToSelector:sel]) {
return [target methodSignatureForSelector:sel];
}else {
return [super methodSignatureForSelector:sel];
}
}
現(xiàn)在服務(wù)映射就寫完了,在控制器中來調(diào)動(dòng)接口:
ServiceProxy *proxy = [ServiceProxy shareProxy];
[proxy getProductInfo:@"123456"];
[proxy submitOrder:@"程序員標(biāo)配的橫條紋T"];
最終的執(zhí)行結(jié)果:demo