第22章 代理
22.1 何为代理模式
远程代理(remote proxy)为位于不同地址空间或网络上的对象提供本地代表。
虚拟代理(virtual proxy)根据需要创建重型对象。
保护代理(protection proxy)根据各种访问权限控制对原对象的访问。
智能引用代理(smart-reference proxy)通过对真正对象的引用进行计数管理内存。也用于锁定真正对象,让其他对象不能对其进行修改。
代理模式:为其他对象提供一种代理一控制对这个对象的访问。
通常,代理是一种代替活着占位,她控制对另一个对象的访问,而这些对象可能是远程对象,创建的开销较大的对象,或者是对安全性有要求的对象。这里没有办法对这些代理作一一介绍。
在运行时,我们可以想象这样一个场景:客户端一抽象类型引用一个对象。这个引用实际上是个Proxy对象。Proxy对象本身有一个对RealSubject实例的引用,以后如果接到请求,此实例将执行高强度的工作。
22.2 何时使用代理模式
22.3 用虚拟代理懒加载图像
涂鸦缩略图视图的设计与实现
//———————————————
@interface ScribbleThumbnailView : UIView
{
@protected
NSString *imagePath_;
}
@property (nonatomic,readonly) UIImage *image;
@property (nonatomic,copy) NSString *imagePath;
@end
#import “ScribbleThumbnailView.h”
#implementation ScribbleThumbnailView
@dynamic image;
@synthesize imagePath= imagePath_;
@end
//———————————————
#import “ScribbleThumbnailView.h”
@interface ScribbleThumbnailViewImageProxy : ScribbleThumbnailView
{
@private
UIImage *realImage_;
BOOL loadingThreadHasLaunched_;
}
@property (nonatomic, readonly) UIImage *image;
@end;
#import “ScribbleThumbnailViewImageProxy.h”
@interface ScribbleThumbnailViewImageProxy()
-(void) forwardImageLoadingThread;
@end
@implementation ScribbleThumbnailViewImageProxy
@dynamic imagePath;
- (UIImage*)image
{
if (realImage_ == nil)
{
realImage_ = [[UIImage alloc] initWithContentOfFile:imagePath_];
}
return realImage_;
}
- (void)drawRect:(CGRect)rect
{
if (realImage_ == nil)
{
//绘制占位图像
}
if(!loadingThreadHasLaunched_)
{
[self performSelectorInBackground:@select(forwardImageLoadingThread) withObject:nil];
loadingThreadHasLaunched_ = YES;
}
else
{
[realImage_ drawInRect:rect];
}
}
- (void)dealloc
{
[realImage_ realease];
[super dealloc];
}
-(void) forwardImageLoadingThread
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self image];
[self performSelectorInMainThread:@selector(setNeedsDispaly) withObject:nil];
[pool release];
}
@end
//———————————————
22.4 在Cocoa Touch框架中使用代理模式
//—————————————————————————
MyProtocol.h
//
// MyProtocol.h
// NSProxyTest
//
// Created by ranzhou on 16/7/6.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import <Foundation/Foundation.h>
@protocol MyProtocol <NSObject>
@optional
-(void)loadImage;
@required
@end
//—————————————————————————
//
// RealObject.h
// NSProxyTest
//
// Created by ranzhou on 16/7/6.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MyProtocol.h"
@interface RealObject : NSObject<MyProtocol>
@end
//—————————————————————————
//
// RealObject.m
// NSProxyTest
//
// Created by ranzhou on 16/7/6.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import "RealObject.h"
@implementation RealObject
-(void)loadImage
{
static dispatch_once_t once;
dispatch_once(&once, ^{
[NSThread sleepForTimeInterval:5.0];
// 第一次加载图像,需要5秒钟。
});
NSLog(@"%@%@",NSStringFromClass([self class]),NSStringFromSelector(_cmd));
}
@end
//—————————————————————————
//
// TestProxy.h
// NSProxyTest
//
// Created by ranzhou on 16/7/6.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MyProtocol.h"
@interface TestProxy : NSProxy<MyProtocol>
//TestProxy中需要实现初始化方法,否则 self.testProxy = [[TestProxy alloc]init];或报编译错误//No visible @interface for 'TestProxy' declares the selector 'init';
//- (instancetype)init;//个人觉得不init也无所谓。
@end
//—————————————————————————
//
// TestProxy.m
// NSProxyTest
//
// Created by ranzhou on 16/7/6.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import "TestProxy.h"
#import "RealObject.h"
@interface TestProxy ()
@property (nonatomic,strong) RealObject *realObject;
@end
@implementation TestProxy
- (RealObject*)toInitRealObject {
static dispatch_once_t once;
dispatch_once(&once, ^{
if (!self.realObject) {
self.realObject = [[RealObject alloc]init];
}
});
return self.realObject;
}
- (void)loadImage {
if (!self.realObject)
{
NSLog(@"随便做点事情,等self.realObject初始化完成再处理");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self toInitRealObject];
[self.realObject loadImage];
});
}
else
{
[self.realObject loadImage];
}
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
if (self.realObject)
{
[invocation setTarget:self.realObject];
[invocation invoke];
}
else
{
NSLog(@"%@%@",@"self.realObject is nil",NSStringFromSelector(_cmd));
}
}
- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
if (self.realObject) {
return [self.realObject methodSignatureForSelector:sel];
}
else
{
NSLog(@"%@%@",@"self.realObject is nil",NSStringFromSelector(_cmd));
return [super methodSignatureForSelector:sel];
}
}
@end
//—————————————————————————
测试代码:
self.testProxy = [TestProxy alloc];
[self.testProxy loadImage];
[self.testProxy loadImage];
}
2016-07-06 21:15:26.276 NSProxyTest[1684:298600] 随便做点事情,等self.realObject初始化完成再处理
2016-07-06 21:15:26.277 NSProxyTest[1684:298600] 随便做点事情,等self.realObject初始化完成再处理
2016-07-06 21:15:31.279 NSProxyTest[1684:298671] RealObjectloadImage
2016-07-06 21:15:31.279 NSProxyTest[1684:298663] RealObjectloadImage
//—————————————————————————