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.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.

这是苹果官方对于NSProxy的解释。这边简单的翻译下:

NSProxy是一个抽象的超类,它定义了一个对象的API,用来充当其他对象或者一些不存在的对象的替身。通常,发送给Proxy的消息会被转发给实际对象,或使Proxy加载(转化为)实际对象。
NSProxy的子类可以用于实现透明的分布式消息传递(例如,NSDistantObject),或者用于创建开销较大的对象的惰性实例化。

众所周知,NSObject类是Objective-C中大部分类的基类。但不是很多人知道除了NSObject之外的另一个基类——NSProxy,NSProxy实现被根类要求的基础方法,包括定义NSObject协议。然而,作为抽象类,它不实现初始化方法,并且会在收到任何它不响应的消息时引发异常。因此,具体子类必须实现一个初始化或者创建方法,并且重写- (void)forwardInvocation:(NSInvocation *)invocation;- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel方法,来转发它没实现的方法。这也是NSProxy的主要功能,负责把消息转发给真正的target的代理类,NSProxy正是代理的意思。

其中,我觉得NSProxy最重要且最核心的一点是消息分发。根据这个特性,我们可以提升项目代码的可维护性,更加模块化。

下面是对NSProxy使用的demo,对消息做分发

/// 农民工协议
@protocol WorkerProtocol 

- (void)beginWork;

@end

NS_ASSUME_NONNULL_BEGIN

@interface Worker : NSObject 

@end

NS_ASSUME_NONNULL_END
/// 码农协议
@protocol ITerProtocol 

- (void)beginCoding;

@end

NS_ASSUME_NONNULL_BEGIN

@interface ITer : NSObject 

@end

NS_ASSUME_NONNULL_END
/// 消息分发中心
@interface MsgDistProxy : NSProxy 
+ (instancetype)sharedInstance;
- (void)registerMethodWithTarget:(id)target;
@end
@interface MsgDistProxy()
@property (nonatomic, strong) NSMutableDictionary *selectorMapDic;
@end

@implementation MsgDistProxy

+ (instancetype)sharedInstance {
    static MsgDistProxy *proxy;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        proxy = [MsgDistProxy alloc];
        proxy.selectorMapDic = [NSMutableDictionary dictionary];
    });
    return proxy;
}

- (void)registerMethodWithTarget:(id)target {
    unsigned int count = 0;
    Method *methodlist = class_copyMethodList([target class], &count);
    for (int i = 0; i < count; i++) {
        Method *method = methodlist[i];
        SEL selector = method_getName(method);
        [self.selectorMapDic setValue:target forKey:[NSString stringWithUTF8String:sel_getName(selector)]];
    }
    free(methodlist);
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    NSString *selector = NSStringFromSelector(sel);
    if ([self.selectorMapDic.allKeys containsObject:selector]) {
        id target = [self.selectorMapDic objectForKey:selector];
        return [target methodSignatureForSelector:sel];
    }
    return [super methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    NSString *selector = NSStringFromSelector(invocation.selector);
    if ([self.selectorMapDic.allKeys containsObject:selector]) {
        id target = [self.selectorMapDic objectForKey:selector];
        [invocation invokeWithTarget:target];
    } else {
        [super forwardInvocation:invocation];
    }
}

@end
    /// 调用
    MsgDistProxy *proxy = [MsgDistProxy sharedInstance];
    
    Worker *worker = [Worker new];
    ITer *iter = [ITer new];
    
    [proxy registerMethodWithTarget:worker];
    [proxy registerMethodWithTarget:iter];
    
    [proxy beginWork];
    [proxy beginCoding];

    /// 输出log
  2019-05-13 17:41:12.148984+0800 proxy[19121:933997] -[Worker beginWork]
  2019-05-13 17:41:12.149197+0800 proxy[19121:933997] -[ITer beginCoding]

你可能感兴趣的:(NSProxy的理解)