天天看點

Objective - C 一一 單例設計模式

1.什麼是設計模式? 

在計算機程式設計語言中有23種設計模式(Design pattern)是一套被反複使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人了解、保證代碼可靠性。毫無疑問,設計模式于己于他人于系統都是多赢的;設計模式使代碼編制真正工程化;設計模式是軟體工程的基石脈絡,如同大廈的結構一樣,在iOS中常用的實際模式為:代理方法,MVC模式,MVVC模式,單例模式等。

什麼是單例設計模式?

單例顧名思義就是說一個類的執行個體隻能有一個,在Java、C++這類語言中,可以通過将構造函數私有化來避免對象的重複建立,

但是Objective-C卻不能夠這樣做,我們需要通過其他機制來達到這個目的。

我們知道,建立對象的步驟分為申請記憶體(alloc)、初始化(init)這兩個步驟,我們要確定對象的唯一性,

是以在第一步這個階段我們就要攔截它。當我們調用alloc方法時,oc内部會調用allocWithZone這個方法來申請記憶體,我們覆寫這個方法,

然後在這個方法中調用shareInstance方法傳回單例對象,這樣就可以達到我們的目的。

拷貝對象也是同樣的原理,覆寫copyWithZone方法,然後在這個方法中調用shareInstance方法傳回單例對象

代碼如下:

#import <Foundation/Foundation.h>

@interface Tools : NSObject
// 一般情況下建立一個單例對象都有一個與之對應的類方法
// 一般情況下用于建立單例對象的方法名稱都以share開頭, 或者以default開頭
+ (instancetype)shareInstance;
@end


#import "Tools.h"

@implementation Tools

+ (instancetype)shareInstance
{
    Tools *instance = [[self alloc] init];
    return instance;
}

// 建立一個空對象
static Tools * _instance = nil;
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    
//    // 目前代碼在多線程中可能會出現問題(多線程并發問題.出現多個線程同時建立對象,線程不安全)
//    NSLog(@"%s",__func__);
//    // 由于所有的建立方法都會調用該方法, 是以隻需要在該方法中控制目前對象隻建立一次即可
//    if (_instance == nil) {
//        NSLog(@"建立了一個對象");
//        _instance = [[super allocWithZone:zone] init];
//        
//    }
//    return _instance;
    
    // 線程安全的單例寫法
    
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [[super allocWithZone:zone] init];
        });
        return _instance;
    
}

// MRC
- (oneway void)release
{
    // 為了保證程式過程中隻有一份執行個體,這個方法什麼都不做.
}

- (instancetype)retain
{
    return _instance;
}

- (NSUInteger)retainCount
{
//    return 1;
    // 注意: 為了友善程式員之間溝通,一般情況下不會再單例中傳回retainCount = 1;
    // 而是傳回一個比較大的值
    return MAXFLOAT;
}

@end
           

效果如下:

main:

#import <Foundation/Foundation.h>
#import "Tools.h"
int main(int argc, const char * argv[]) {
    
    // 單例就是無論怎麼建立都隻能有一個執行個體對象
    // 如果位址相同就代表着是同一個執行個體對象
    
    Tools *t1 = [[Tools alloc] init]; //内部會調用 allocWithZone
    Tools *t2 = [Tools new];          // [[alloc] init]  allocWithZone
    Tools *t3 = [Tools shareInstance];
    NSLog(@"t1 = %p",t1);
    NSLog(@"t2 = %p",t2);
    NSLog(@"t3 = %p",t3);
    
    
//    Tools *t2 = [[Tools alloc] init];
//    [t2 retain];
//    [t2 retain];
//    [t2 retain];
//    [t2 retain];
//    NSLog(@"retainCount = %lu",[t2 retainCount]);
//    NSLog(@"t2 = %p",t2);
//    [t2 release];
//    
//    Tools *t1 = [Tools shareInstance];
//    NSLog(@"t1 = %p",t1);
//    [t1 release];

    
    return 0;
}
           

輸出結果:

ARC輸出結果:

2017-07-30 23:09:29.707705+0800 單例ARC寫法和MRC寫法[5474:213457] t1 = 0x100202690
2017-07-30 23:09:29.707915+0800 單例ARC寫法和MRC寫法[5474:213457] t2 = 0x100202690
2017-07-30 23:09:29.707931+0800 單例ARC寫法和MRC寫法[5474:213457] t3 = 0x100202690
           

MRC輸出結果:(上方main方法中,注釋的代碼打開)

2017-07-30 23:10:11.185137+0800 單例ARC寫法和MRC寫法[5498:213824] retainCount = 4298126752
2017-07-30 23:10:11.185336+0800 單例ARC寫法和MRC寫法[5498:213824] t2 = 0x1003035a0
2017-07-30 23:10:11.185364+0800 單例ARC寫法和MRC寫法[5498:213824] t1 = 0x1003035a0
           

注意:這裡我解釋一下.在Tools的.m方法中.如果是ARC的情況.不必要重寫release,retain,retainCount方法.

如果是MRC,要想實作單例,必須重寫這個三個方法.

從輸出結果上來,對象的位址都是一樣的,說明是同一塊存儲空間.這樣就隻建立了一個對象.

上一篇: 杭電acm1272

繼續閱讀