IOS設計模式----物件池模式OBJC版
本案例通過使用物件池模式來複用一個UILabel,效果圖如下:
一.物件池的作用簡單介紹:
1. 提升物件的使用效率。
在使用大量存活率很短,但邏輯基本相似的情況下,反覆的建立物件會消費大量的時間。
而這個時間主要開銷在給物件開闢記憶體空間。物件池模式通過複用這些物件來減少物件的建立從而
達到提升效能。
二.角色分析。
1.可用物件引用列表,功能:
回收物件,並將該物件存入本列表中,下一次再建立物件的時候,
先從判斷本列表中是否有可用元素,如果有則直接取出,否則建立新的物件。
2.正在使用物件引用列表,功能:
儲存正在使用物件引用,建立物件的時候,先判斷可用列表是否有可用物件
如果有可用物件直接取出來,並將該物件從可用列表中移除;
如果沒有可用物件則建立一個新物件,並將該物件的引用存入正在使用列表;
函式角色及功能分析如下:
1.驗證物件的有效性的函式,保證在取物件的時候取出的物件的有效性;
當被驗證的物件無效時,如果該物件存在於可用列表中,需要從該列表中
移除並回收記憶體;
2.回收物件的函式,主要用於回收無效物件所佔用的記憶體;
3.取物件函式,邏輯:
a.先判斷可用列表中是否有物件,如果有則取出該物件並進行驗證,
如果有效直接返回,否則進行物件回收處理
b.當步驟a失效時,建立新的物件並將該物件引用存入正在使用的列表中同時
返回該物件給使用者
注意:考慮到這個函式的執行緒安全性,需要將本函式設計為執行緒安全的
4.回收物件函式,邏輯:
a.將該物件從正在使用列表中移除,同時判斷這個是否還有效
如果有效,則進入可用列表,否則直接回收物件
注意:考慮到這個函式的執行緒安全性,需要將本函式設計為執行緒安全的
三.程式碼設計
為了提高物件物件池的使用靈活性,這裡將函式功能角色封裝為介面,具體的邏輯由子類支實現
介面程式碼為:
物件池基類:@protocol ObjPoolListener<NSObject> @required -(id) create; -(BOOL) validate:(id) obj; //驗證物件的有效性 -(void) recycObj:(id) obj; //回收物件 -(id) getObjFromPool; //獲取物件 -(void) putObj2Pool:(id) obj; //將物件放回池中 @end
@interface BaseObjPool : NSObject<ObjPoolListener>
@property(nonatomic,strong) NSMutableArray* inUseList;
@property(nonatomic,strong) NSMutableArray* availableList;
@end
基類.m檔案:
#import "BaseObjPool.h"
@implementation BaseObjPool
-(id) init{
if(self = [super init]){
self.inUseList = [NSMutableArray array];
self.availableList = [NSMutableArray array];
}
return self;
}
/*****************************************
*
*實現協議介面
*
****************************************/
-(id) getObjFromPool{
__block id tmpObj;
if(self.availableList.count > 0){
[self.availableList enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL* _Nonnull stop){
tmpObj = obj;
if([self validate:obj]){
[self.availableList removeObject:tmpObj];
[self.inUseList addObject:tmpObj];
*stop = YES;
}else{
[self.availableList removeObject:tmpObj];
[self recycObj:tmpObj];
*stop = true;
}
}];
}else{
tmpObj = [self create];
[self.inUseList addObject:tmpObj];
}
return tmpObj;
}
/**
將物件放回池中:
1.先將物件從正在使用列表中移除
2.判斷這個物件是否被外部呼叫者置為無效狀態,如果被置為無效狀態,則直接回收;
否則將其新增到可用列表中,以備下次建立物件時進行復用
@param obj 待放回的物件
*/
-(void) putObj2Pool:(id)obj{
[self.inUseList removeObject:obj];
if([self validate:obj]){
[self.availableList addObject:obj];
}else{
[self recycObj:obj];
}
}
//需要子類重寫
-(id) create{
return [[NSObject alloc] init];
}
/**
驗證物件是否還有效,此處的驗證條件預設為,該物件是否為空
通常需要子類進行重寫
@param obj 待驗證的物件
@return 返回驗證結果
*/
-(BOOL)validate:(id)obj{
return obj != nil;
}
/**
回收物件
@param obj 待回收的物件
*/
-(void) recycObj:(id)obj{
obj = nil;
}
/*****************************************
*
*實現協議介面--end
*
****************************************/
@end
測試用的標籤池:
#import <UIKit/UIKit.h>
#import "BaseObjPool.h"
@interface ViewPool : BaseObjPool
@property(nonatomic,strong) UILabel* textView;
@end
.m檔案:
#import "ViewPool.h"
@implementation ViewPool
-(id) init{
if(self = [super init] ){
}
return self;
}
-(id) create{
self.textView = [[UILabel alloc] init];
self.textView.text = [NSString stringWithFormat:@"%d",arc4random() % 100];
return self.textView;
}
-(BOOL) validate:(id)obj{
//return self.textView != nil;
return obj != nil;
}
-(void) recycObj:(id)obj{
//self.textView = nil;
obj = nil;
}
@end
在VC中的測試程式碼:
#import "ViewController.h"
#import "ViewPool.h"
@interface ViewController ()
@property(nonatomic,strong)ViewPool* mPool;
@property(nonatomic,assign)NSInteger nProduceCount;
@property(nonatomic,assign)NSInteger nCoustmerCount;
@end
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
[selfinitView];
self.mPool = [[ViewPoolalloc] init];
self.nProduceCount =2;
self.nCoustmerCount =1;
}
-(void) initView{
UIButton* createObj = [[UIButtonalloc] initWithFrame:CGRectMake(10,40, 80,40)];
[createObj setTitle:@"建立物件"forState:UIControlStateNormal];
createObj.backgroundColor = [UIColorgrayColor];
createObj.tag =21;
[createObj addTarget:selfaction:@selector(onClick:)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:createObj];
UIButton* recycObj = [[UIButtonalloc] initWithFrame:CGRectMake(100,40, 130,40)];
[recycObj setTitle:@"回收物件到池中"forState:UIControlStateNormal];
recycObj.backgroundColor = [UIColorgrayColor];
recycObj.tag =22;
[recycObj addTarget:selfaction:@selector(onClick:)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:recycObj];
UIButton* destoryObj = [[UIButtonalloc] initWithFrame:CGRectMake(235,40, 100,40)];
[destoryObj setTitle:@"銷燬物件"forState:UIControlStateNormal];
destoryObj.backgroundColor = [UIColorgrayColor];
destoryObj.tag =23;
[destoryObj addTarget:selfaction:@selector(onClick:)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:destoryObj];
}
-(void) onClick:(UIButton*) button{
switch (button.tag) {
case21:{
[selfproduceObj];
}
break;
case22:{
[selfputObj2Pool];
}
break;
case23:
[selfdestoryObj];
break;
default:
break;
}
}
-(void) produceObj{
UILabel* tmpView = [self.mPoolgetObjFromPool];
tmpView.frame =CGRectMake(50, self.nProduceCount *50, 100,40);
tmpView.backgroundColor = [UIColorgrayColor];
self.nProduceCount +=1;
tmpView.tag =self.nProduceCount;
[self.viewaddSubview:tmpView];
}
-(void) putObj2Pool{
[self.mPoolputObj2Pool:[self.viewviewWithTag:self.nProduceCount]];
[[self.viewviewWithTag:self.nProduceCount]removeFromSuperview];
self.nProduceCount -=1;
}
-(void) destoryObj{
UILabel* tmpLabel = [self.viewviewWithTag:self.nProduceCount];
if(tmpLabel){
[tmpLabel removeFromSuperview];
[self.mPoolrecycObj:tmpLabel];
self.nProduceCount -=1;
}
}
- (void)didReceiveMemoryWarning {
[superdidReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end