- 代理模式
- 代理与协议
- 用NSProxy实现代理模式
-
代理模式的基本原理
代理模式实际上就是一个对象和另外一个对象的耦合,我们为了降低耦合度。用抽象的代理来实现功能。 -
使用代理模式需要注意的地方
weak 是否响应 -
经销商和顾客
假设主控制器ViewController是经销商,我们来写一个顾客类 然后写一个ViewController属性
然后写一个方法用来调用ViewController方法,同时传递顾客买东西行为,和数量
// 顾客
#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
-
(void)custmerBuyActionWithCount:(NSInteger)count{
if (self.viewController) {
// 购买数量传递给经销商
[self.viewController custmerBuyActionsWithCount:count];
}
}
@end``` -
经销商(ViewController)
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
- (void)custmerBuyActionsWithCount:(NSInteger)count; (接收方法)
@end```
import "ViewController.h"
import "Custmer.h"
// 经销商
@interface ViewController ()
@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.viewController = self; (指定经销商)
[custmer custmerBuyActionWithCount:5];
}
// 实现传递方法传递过来的值
-
(void)custmerBuyActionsWithCount:(NSInteger)count{
NSLog(@"%ld",count);
} -
(void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end```
- 运行结果:
-
上面我们用了一个简单的例子说明了代理的原理,我们用一个对象去弱引用另一个对象,为这个对象传值,通过调用本对象的方法来实现给另一个对象传值,从而实现对象间互通。
但是这里的经销商是一个指定的对象,但是我们写代码的时候如果有不同的对象需要知道该顾客的行为呢? -
下面我们来修改使其成为一个通用的代理
// 顾客
#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
- (void)custmerBuyActionWithCount:(NSInteger)count{
// 如果代理存在 并且可以响应代理方法
if (self.delegate && [self.delegate respondsToSelector:@selector(custmerBuyWithCount:custmer:)]) {
// 执行代理方法
[self.delegate custmerBuyWithCount:count custmer:self];
}
}
@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
-
(NSInteger)sourcePort; // 获取源端口号
-
(NSInteger)destinationPort; // 获取目的地端口号
@end```
-
引入协议
Paste_Image.png -
使用协议
#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
- (instancetype)shareInstance;
@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
- (void)helloWolrd;
- (void)goodBey;
@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实现代理模式
网友评论