1. 程式人生 > >IOS設計模式----物件池模式OBJC版

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