一直想花時(shí)間把之前項(xiàng)目常用的控件及功能整理出來,本打算把AFNetworking二次封裝下,想到需要使用單例來封裝AFHTTPSessionManager類,看到很多使用單例的方法處理不夠嚴(yán)謹(jǐn),這里還是單獨(dú)拎出來,把單例的用法講一下。
知識(shí)點(diǎn)
1.alloc int 的功能及調(diào)用順序
2.allocWithZone 的調(diào)用
3.單列的實(shí)現(xiàn)原理及正確使用
1.alloc init 的使用
我們通常創(chuàng)建一個(gè)oc對(duì)象的時(shí)候,一般都是使用alloc init方法。
alloc 給對(duì)象分配內(nèi)存空間
init 初始化該對(duì)象
我們通常會(huì)這么創(chuàng)建對(duì)象
person * p1 = [[person alloc]init];
這樣操作,就完成一個(gè)對(duì)象的創(chuàng)建過程。
那么系統(tǒng)在什么時(shí)候給對(duì)象分配內(nèi)存空間呢?其實(shí)當(dāng)我們執(zhí)行alloc方法的時(shí)候,系統(tǒng)會(huì)自動(dòng)調(diào)用他如下方法來為對(duì)象分配內(nèi)存地址
+ (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
我們點(diǎn)擊進(jìn)去可以查看到

這是NSObject的方法,也就是只要是oc對(duì)象,都擁有此方法。
其實(shí)創(chuàng)建對(duì)象,也就是創(chuàng)建一個(gè)類型的指針,創(chuàng)建的時(shí)候分配內(nèi)存地址。
person * p1 = [[person alloc]init];//執(zhí)行順序如下
// 1.alloc
// 2.+ (instancetype)allocWithZone
// 3.init
還是看代碼來驗(yàn)證
我們創(chuàng)建一個(gè)常用的person類
#import "person.h"
@implementation person
//調(diào)用順序 如下
-(instancetype)init{
if (self = [super init])// 3
{
}
return self;// 4
}
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
static person *person = nil;
person = [super allocWithZone:zone];// 1
return person;// 2
}
在外部調(diào)用
person * p1 = [[person alloc]init];
編譯項(xiàng)目,看行執(zhí)行順序

編譯順序,如上注釋。
我們來創(chuàng)建三個(gè)person對(duì)象
person * p1 = [[person alloc]init];
person * p2 = [[person alloc]init];
person * p3 = [[person alloc]init];
NSLog(@"%@ \n %@ \n %@",p1,p2,p3);
打印內(nèi)存地址
<person: 0x60000001fa90>
<person: 0x60000001fb60>
<person: 0x60000001fb50>
每次創(chuàng)建對(duì)象,都會(huì)分配新的內(nèi)存地址。其實(shí)創(chuàng)建oc對(duì)象的就是創(chuàng)建了一個(gè)對(duì)象類型的指針,分配內(nèi)存地址,之后讓指針指向自己的內(nèi)存控件,之后再init方法實(shí)現(xiàn)對(duì)對(duì)象的初始化,擁有調(diào)用自己屬性和方法的權(quán)利。
單例使用常用方法
單例是在整個(gè)工程中只擁有一個(gè)該類實(shí)例。
1.單例使用
我們來看下,我們通常創(chuàng)建單例的方法
+(instancetype)sharedInstance;
{
static person *single = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
single =[[self alloc]init];
});
return single;
}
這里,我們使用GCD提供的dispatch_once的方法,在這個(gè)方法內(nèi)部使用創(chuàng)建對(duì)象的[[self alloc]init]方法,保證這個(gè)方法只執(zhí)行一遍。
我們創(chuàng)建單列如下
person * p4 = [person sharedInstance];
person * p5 = [person sharedInstance];
person * p6 = [person sharedInstance];
NSLog(@"%@ \n %@ \n %@",p4,p5,p6);
打印內(nèi)存地址如下
<person: 0x60c00000cc00>
<person: 0x60c00000cc00>
<person: 0x60c00000cc00>
通過驗(yàn)證,的確返回的同一個(gè)實(shí)例,我們的目標(biāo)達(dá)到了?
問題
可是如果還是用以下方法,還會(huì)返回同一個(gè)實(shí)例對(duì)象嘛
person * p1 = [[person alloc]init];
我們來驗(yàn)證下
person * p1 = [[person alloc]init];
person * p2 = [[person alloc]init];
person * p3 = [[person alloc]init];
NSLog(@"%@ \n %@ \n %@",p1,p2,p3);
person * p4 = [person sharedInstance];
person * p5 = [person sharedInstance];
person * p6 = [person sharedInstance];
NSLog(@"%@ \n %@ \n %@",p4,p5,p6);
打印內(nèi)存地址如下
<person: 0x60000001fa90>
<person: 0x60000001fb60>
<person: 0x60000001fb50>
<person: 0x60c00000cc00>
<person: 0x60c00000cc00>
<person: 0x60c00000cc00>
可見通過alloc init方法創(chuàng)建的對(duì)象,還是分配的不同的內(nèi)存空間。
我們?cè)撛趺幢苊膺@樣的現(xiàn)象發(fā)生呢?
單例使用完善
這里我們重寫系統(tǒng)創(chuàng)建對(duì)象時(shí)分配內(nèi)存地址的方法,并把創(chuàng)建單例方法寫在此方法中,保證每次創(chuàng)建對(duì)象都返回同一個(gè)內(nèi)存空間
// 把創(chuàng)建單例的寫法寫在系統(tǒng)為對(duì)象分配內(nèi)存地址的方法中
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
static person * single = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
single = [super allocWithZone:zone];// 最先執(zhí)行,只執(zhí)行一次
});
return single;
}
使用方法如下
// sharedInstance方法中,返回的是[[self alloc]init]方法返回的實(shí)例
+(instancetype)sharedInstance
{
return [[self alloc]init];// 這里會(huì)調(diào)用init方法
}
// init方法,重寫init方法
-(instancetype)init
{
if (self = [super init]) {
}
return self;
}
// 把創(chuàng)建單例的寫法寫在系統(tǒng)為對(duì)象分配內(nèi)存地址的方法中
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
static person * single = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 記住這里只會(huì)執(zhí)行一次
single = [super allocWithZone:zone];// 最先執(zhí)行,只執(zhí)行一次
});
return single;
}
通過代碼來驗(yàn)證下
person * p1 = [[person alloc]init];
person * p2 = [[person alloc]init];
person * p3 = [[person alloc]init];
NSLog(@"%@ \n %@ \n %@",p1,p2,p3);
person * p4 = [person sharedInstance];
person * p5 = [person sharedInstance];
person * p6 = [person sharedInstance];
NSLog(@"%@ \n %@ \n %@",p4,p5,p6);
<person: 0x60800000a3e0>
<person: 0x60800000a3e0>
<person: 0x60800000a3e0>
<person: 0x60800000a3e0>
<person: 0x60800000a3e0>
<person: 0x60800000a3e0>
返回來了同一個(gè)實(shí)例,不管用alloc init創(chuàng)建還是直接用sharedInstance這個(gè)方法。
這樣的創(chuàng)建方法,比我們文中提到的常用創(chuàng)建的單例方法更完善。
[end]