書寫一個嚴謹的單例

c4ibD3發表於2018-01-19

前言

什麼是單例?

一個類只有一個例項(一個物件),而且該例項易於供外界訪問,從而方便地控制了例項個數,並節約系統資源

正題

在iOS開發中單例是很平常的模式,但是昨天去面試的時候被人問到了一個比較尷尬的問題。 平常在專案中我們書寫的單例大概應該都是這個樣子,現在.h檔案中宣告一個類方法

@implementation Singleton

+(instancetype)shareInstance;

@end
複製程式碼

然後在.m中去實現這個方法

@implementation Singleton

static Singleton *instance = nil;

+(instancetype)shareInstance{
    static dispatch_once_t onceToken;
    dispath_once(&onceToken,^{
        instance = [[self alloc]init];
    });
    return instance;
}
複製程式碼

但是,昨天有人問了這麼一個問題,說一般的都知道這個類方法是建立單例的,假如我不知道,我直接走了[[self alloc]init]方法來建立這個物件。那是不是就不能保證這個物件類的唯一性了?
仔細想一下好像是這樣,這也是我個人的問題。在寫專案的時候沒有注意到這麼個問題。在當時那個是時候我是被難住了...... 之後我就寫了一個demo試了一下

單例
這時我們再看看控制檯中列印出來的資訊
書寫一個嚴謹的單例
single1single2的地址是一樣的,因為都是走了那個類方法,可是single3就不一樣了,這個時候這個Singleton就不嚴謹了。

解決問題

之後我就去網上找了一下,網上真的有很多人已經寫過這樣的技術部落格了。我就去試了試。
主要就是為了確保物件的唯一性,所以我們需要封鎖使用者通過alloc和init以及copy來構造物件的這條路。
在建立物件的時候主要分這麼兩步 alloc (申請記憶體)init(初始化)
1.我們在第一步alloc的會後就要對其進行攔截。當我們去呼叫alloc的時候,OC內部會呼叫allocWithZone這個方法去申請記憶體,我們去覆寫這個方法,然後在這個方法中呼叫之前的類方法,返單例物件,這樣就能達到我們的目的了。
2.拷貝物件也是一樣的,覆寫copyWithZone方法,然後在方法中去呼叫類方法,返回單例物件。(在覆寫copyWithZone方法之前別忘記了簽署NSCopying協議)

類方法中也有做些許改動

#import <Foundation/Foundation.h>

@interface Singleton : NSObject<NSCopying>

+(instancetype)sharedInstance;

@end
#import "Singleton.h"

@implementation Singleton

static Singleton *instance = nil;

+(instancetype)sharedInstance{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{
//        instance = [[self alloc]init];
        instance = [[super allocWithZone:NULL]init];
    });
    return instance;
}
+(id)allocWithZone:(struct _NSZone *)zone{
    return [Singleton sharedInstance];
}
-(id)copyWithZone:(NSZone *)zone{
    return [Singleton sharedInstance];
}
@end
複製程式碼

接下來我們再看看通過不同方式建立之後的地址是否相同

書寫一個嚴謹的單例
控制檯的輸出

書寫一個嚴謹的單例

宣告

本人並不是一個技術大神,只是一個菜鳥而已,寫這個文章也不是為了炫耀什麼,只是記錄一下自己工作中的問題&如何解決。

相關文章