https://github.com/YouXianMing

iOS设计模式 - 代理

iOS设计模式 - 代理

 

原理图

 

说明

1. 代理模式大家都用过,但用抽象基类NSProxy实现代理估计鲜有人用

2. 本人用NSProxy实现了代理模式,对于理解消息转发机制有点帮助

 

源码

https://github.com/YouXianMing/iOS-Design-Patterns

//
//  AbstractProxy.h
//  AppProxy
//
//  Created by YouXianMing on 15/8/4.
//  Copyright (c) 2015年 YouXianMing. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface AbstractProxy : NSProxy

/**
 *  被代理对象
 */
@property (nonatomic, weak) id  customer;

/**
 *  代理客户
 *
 *  @param customer 实现了某种协议的客户
 *
 *  @return 代理对象
 */
- (instancetype)initWithCustomer:(id)customer;

@end
//
//  AbstractProxy.m
//  AppProxy
//
//  Created by YouXianMing on 15/8/4.
//  Copyright (c) 2015年 YouXianMing. All rights reserved.
//

#import <objc/runtime.h>
#import "AbstractProxy.h"
#import "AbstractExcute.h"

@implementation AbstractProxy

- (instancetype)initWithCustomer:(id)customer {

    self.customer = customer;
    return self;
}

#pragma mark - NSProxy

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    
    if ([self.customer respondsToSelector:aSelector]) {
        
        return [self.customer methodSignatureForSelector:aSelector];
        
    } else {
        
        AbstractExcute *excute = [AbstractExcute shareInstance];
        return [excute methodSignatureForSelector:NSSelectorFromString(@"nullExcute:")];
    }
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    
    SEL selector = [invocation selector];
    if ([self.customer respondsToSelector:selector]) {
        
        [invocation setTarget:self.customer];
        [invocation invoke];
        
    } else {
    
        NSString *selectorString = NSStringFromSelector(invocation.selector);
        
        invocation.selector    = NSSelectorFromString(@"nullExcute:");
        AbstractExcute *excute = [AbstractExcute shareInstance];
        [invocation setTarget:excute];
        
        const char *className      = class_getName([self class]);
        NSArray    *classNameArray = nil;
        if (self.customer) {
            
            classNameArray = @[[NSString stringWithUTF8String:className], selectorString, @""];
            
        } else {
        
            classNameArray = @[[NSString stringWithUTF8String:className], selectorString];
        }
        
        [invocation setArgument:&classNameArray atIndex:2];
        [invocation invoke];
    }
}

@end
//
//  AbstractExcute.h
//  AppProxy
//
//  Created by YouXianMing on 15/8/4.
//  Copyright (c) 2015年 YouXianMing. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface AbstractExcute : NSObject

+ (instancetype)shareInstance;

@end
//
//  AbstractExcute.m
//  AppProxy
//
//  Created by YouXianMing on 15/8/4.
//  Copyright (c) 2015年 YouXianMing. All rights reserved.
//

#import "AbstractExcute.h"

@implementation AbstractExcute

+ (instancetype)shareInstance {

    static AbstractExcute *sharedAbstractExcute = nil;
    
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        sharedAbstractExcute = [[self alloc] init];
    });
    
    return sharedAbstractExcute;
}

- (void)nullExcute:(NSArray *)className {

    if (className.count == 3) {
        
        NSLog(@"%@ 设置了代理,但该代理没有实现 %@ 方法", className[0], className[1]);
        
    } else {
    
        NSLog(@"%@ 没有设置代理,方法 %@ 没有执行", className[0], className[1]);
    }
    
}

@end

 

细节

NSProxy子类实现的关键所在

 

posted @ 2015-08-04 21:59  YouXianMing  阅读(592)  评论(0编辑  收藏  举报