技术

代理模式

2015-11-19  本文已影响303人  952625a28d0d
Paste_Image.png
// 顾客
#import <Foundation/Foundation.h>
#import "ViewController.h"

@interface Custmer : NSObject

@property (nonatomic, weak) ViewController *viewController;

// 顾客买卖行为
- (void)custmerBuyActionWithCount:(NSInteger)count;

@end```

import "Custmer.h"

@implementation Custmer

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

- (void)custmerBuyActionsWithCount:(NSInteger)count; (接收方法)

@end```

import "ViewController.h"

import "Custmer.h"

// 经销商
@interface ViewController ()

@end

@implementation ViewController

// 实现传递方法传递过来的值

@end```

Paste_Image.png
// 顾客
#import <Foundation/Foundation.h>
#import "ViewController.h"

@class Custmer; // 声明下面出现的类
@protocol custmerDelegate <NSObject>

@required
- (void)custmerBuyWithCount:(NSInteger)count custmer:(Custmer *)custmer;    // 必须实现的代理方法

@end

@interface Custmer : NSObject

@property (nonatomic, weak) id<custmerDelegate> delegate;   // 弱引用的代理属性

// 顾客买卖行为
- (void)custmerBuyActionWithCount:(NSInteger)count; // 调用方法

@end```

import "Custmer.h"

@implementation Custmer

@end```

#import "ViewController.h"
#import "Custmer.h"

// 经销商
@interface ViewController ()<custmerDelegate>   // 遵守代理

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    Custmer *custmer = [[Custmer alloc] init];
    custmer.delegate = self;    // 设置代理
    [custmer custmerBuyActionWithCount:5];  
}

#pragma mark 实现代理方法
- (void)custmerBuyWithCount:(NSInteger)count custmer:(Custmer *)custmer{
    NSLog(@"%ld~~%@",count,custmer);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end```

- 运行结果:

![Paste_Image.png](http:https://img.haomeiwen.com/i189984/62cf6595279d2e0d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

以上我们就实现了一个通用的代理。
也就是说现在Customer可以服务的对象是任何遵守了他的协议的对象。这就降低了对象与对象之间的耦合度,我们的代理并不用关心使用的对象是谁,而要关心是否遵守了代理协议并设置了代理对象。
使用代理的时候一定要注意一下几点:
1:声明协议的时候经常需要将代理对象传递出去,所以用@class进行声明。
2:避免循环引用,所以属性一定要写成weak
3:写代理方法的时候要写明白是requied还是option
4:使用代理的时候一定要验证代理是否存在并且是否可以执行代理方法,不然可能造成不必要的崩溃。

#####代理与协议的区别
- 代理的职能
降低对象之间的耦合度
- 协议
约束对象、筛选对象
- 相似性:
他们两者都是用protocol声明

下面我们来创建一个协议:


![Paste_Image.png](http:https://img.haomeiwen.com/i189984/e80cb6b33cf39ce7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

import <Foundation/Foundation.h>

@protocol TCPProtocol <NSObject>

@required

@end```

#pragma mark - 获取协议的源端口号和目的地端口号
- (void)accessTCPData:(id<TCPProtocol>)data{
    self.sourcePort = [data sourcePort];
    self.destinationPort = [data destinationPort];
}```

 - 如果一个模型遵循了我们写的协议

import <Foundation/Foundation.h>

import "TCPProtocol.h"

@interface Model : NSObject<TCPProtocol>

@end```

#import "Model.h"

@implementation Model

#pragma mark - 实现协议方法
- (NSInteger)sourcePort{
    return 10;
}// 获取源端口号

- (NSInteger)destinationPort{
    return 10;
}// 获取目的地端口号

@end```

那么我们以上在ViewController里面获取协议源端口号和目的地端口号则可以用Model中所实现的协议方法中的值,因为Model实现了协议方法。
所以说协议是为了约束对象。规范接口。和代理是完全不一样的。

#####用NSProxy来实现代理模式
NSProxy是一个继承于NSObject的类 

- NSProxy中的消息传递机制
- NSProxy的用途
- 用NSProxy来实现代理模式

1:首先写一个继承自NSProxy的类

import <Foundation/Foundation.h>

@interface AbastarctProxy : NSProxy

@property (nonatomic, weak) id delegate;

@end```

#import "AbastarctProxy.h"
#import "AbastarcExcute.h"
#import <objc/runtime.h>

@implementation AbastarctProxy

#pragma mark - 验证方法签名
- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
    if ([self.delegate respondsToSelector:sel]) {
        return [self.delegate methodSignatureForSelector:sel];
    }else{
        
        // 方法签名扔到处理专门处理的单例类中
        AbastarcExcute *excute = [AbastarcExcute shareInstance];
        return [excute methodSignatureForSelector:NSSelectorFromString(@"nullExcute:")];
    }
}

#pragma mark 派发信息
- (void)forwardInvocation:(NSInvocation *)invocation{
    
    // 获取方法
    SEL selecter = [invocation selector];
    // 如果代理能够响应方法
    if ([self.delegate respondsToSelector:selecter] ) {
        // 设置代理
        [invocation setTarget:self.delegate];
        // 执行方法
        [invocation invoke];
    }else{
        // 获取没有替换之前的selector
        NSString *selectorString = NSStringFromSelector(invocation.selector);
        invocation.selector = NSSelectorFromString(@"nullExcute:");
        AbastarcExcute *excute = [AbastarcExcute shareInstance];
        [invocation setTarget:excute];
        const char *className = class_getName([self class]);    // 获取当前的class类
        NSArray *infos = nil;
        if (self.delegate) {
            infos = @[[NSString stringWithUTF8String:className],selectorString,@""];
        }else{
            infos = @[[NSString stringWithUTF8String:className],selectorString];
        }
        [invocation setArgument:&infos atIndex:2];
        [invocation invoke];
    }
}

@end```

2:写一个处理垃圾消息的单例类即没有代理或者代理不响应协议方法的时候

// 处理垃圾消息的类

import <Foundation/Foundation.h>

@interface AbastarcExcute : NSObject

@end```

#import "AbastarcExcute.h"

@implementation AbastarcExcute

+ (instancetype)shareInstance{
    static AbastarcExcute *excute = nil;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        excute = [[AbastarcExcute alloc] init];
    });
    return excute;
}

- (void)nullExcute:(NSArray *)infos{
    NSLog(@"%@",infos);
}

@end```

3:写一个协议

import <Foundation/Foundation.h>

@protocol MessageProtocol <NSObject>

@optional

@end```

4:写一个类遵守该协议

#import "AbastarctProxy.h"
#import "MessageProtocol.h"

@interface ConcreatProxy : AbastarctProxy<MessageProtocol>

@end```

import "ConcreatProxy.h"

@implementation ConcreatProxy

@end```

5:主控制器调用

#import "ViewController.h"
#import "ConcreatProxy.h"

@interface ViewController ()<MessageProtocol>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    ConcreatProxy *proxy = [ConcreatProxy alloc];   // 这个代理只有alloc方法
    proxy.delegate = self;
    [proxy helloWolrd]; // 让代理执行helloworld
}

- (void)helloWolrd{
    NSLog(@"xxxxx");
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end```

6:输出结果

![Paste_Image.png](http:https://img.haomeiwen.com/i189984/5e254fbd3d2d18d1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

#####需要掌握的
- 代理模式
- 代理与协议的区别
- 用NSProxy实现代理模式
上一篇 下一篇

猜你喜欢

热点阅读