第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
//—————————————————————————