前言
什麼是單例?
一個類只有一個例項(一個物件),而且該例項易於供外界訪問,從而方便地控制了例項個數,並節約系統資源
正題
在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試了一下
single1
和single2
的地址是一樣的,因為都是走了那個類方法,可是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
複製程式碼
接下來我們再看看通過不同方式建立之後的地址是否相同
控制檯的輸出宣告
本人並不是一個技術大神,只是一個菜鳥而已,寫這個文章也不是為了炫耀什麼,只是記錄一下自己工作中的問題&如何解決。