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,要想實作單例,必須重寫這個三個方法.
從輸出結果上來,對象的位址都是一樣的,說明是同一塊存儲空間.這樣就隻建立了一個對象.