一直想花時間把之前項目常用的控件及功能整理出來像棘,本打算把AFNetworking二次封裝下施掏,想到需要使用單例來封裝AFHTTPSessionManager類鄙麦,看到很多使用單例的方法處理不夠嚴謹应媚,這里還是單獨拎出來,把單例的用法講一下缺猛。
知識點
1.alloc int 的功能及調(diào)用順序
2.allocWithZone 的調(diào)用
3.單列的實現(xiàn)原理及正確使用
1.alloc init 的使用
我們通常創(chuàng)建一個oc對象的時候,一般都是使用alloc init方法椭符。
alloc 給對象分配內(nèi)存空間
init 初始化該對象
我們通常會這么創(chuàng)建對象
person * p1 = [[person alloc]init];
這樣操作荔燎,就完成一個對象的創(chuàng)建過程。
那么系統(tǒng)在什么時候給對象分配內(nèi)存空間呢销钝?其實當我們執(zhí)行alloc方法的時候有咨,系統(tǒng)會自動調(diào)用他如下方法來為對象分配內(nèi)存地址
+ (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
我們點擊進去可以查看到
這是NSObject的方法,也就是只要是oc對象蒸健,都擁有此方法座享。
其實創(chuàng)建對象,也就是創(chuàng)建一個類型的指針似忧,創(chuàng)建的時候分配內(nèi)存地址渣叛。
person * p1 = [[person alloc]init];//執(zhí)行順序如下
// 1.alloc
// 2.+ (instancetype)allocWithZone
// 3.init
還是看代碼來驗證
我們創(chuàng)建一個常用的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];
編譯項目,看行執(zhí)行順序
編譯順序盯捌,如上注釋诗箍。
我們來創(chuàng)建三個person對象
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)建對象,都會分配新的內(nèi)存地址。其實創(chuàng)建oc對象的就是創(chuàng)建了一個對象類型的指針滤祖,分配內(nèi)存地址筷狼,之后讓指針指向自己的內(nèi)存控件,之后再init方法實現(xiàn)對對象的初始化匠童,擁有調(diào)用自己屬性和方法的權利埂材。
單例使用常用方法
單例是在整個工程中只擁有一個該類實例。
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的方法,在這個方法內(nèi)部使用創(chuàng)建對象的[[self alloc]init]方法扬绪,保證這個方法只執(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>
通過驗證,的確返回的同一個實例挤牛,我們的目標達到了莹痢?
問題
可是如果還是用以下方法,還會返回同一個實例對象嘛
person * p1 = [[person alloc]init];
我們來驗證下
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)建的對象墓赴,還是分配的不同的內(nèi)存空間竞膳。
我們該怎么避免這樣的現(xiàn)象發(fā)生呢?
單例使用完善
這里我們重寫系統(tǒng)創(chuàng)建對象時分配內(nèi)存地址的方法诫硕,并把創(chuàng)建單例方法寫在此方法中坦辟,保證每次創(chuàng)建對象都返回同一個內(nèi)存空間
// 把創(chuàng)建單例的寫法寫在系統(tǒng)為對象分配內(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]方法返回的實例
+(instancetype)sharedInstance
{
return [[self alloc]init];// 這里會調(diào)用init方法
}
// init方法锉走,重寫init方法
-(instancetype)init
{
if (self = [super init]) {
}
return self;
}
// 把創(chuàng)建單例的寫法寫在系統(tǒng)為對象分配內(nèi)存地址的方法中
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
static person * single = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 記住這里只會執(zhí)行一次
single = [super allocWithZone:zone];// 最先執(zhí)行,只執(zhí)行一次
});
return single;
}
通過代碼來驗證下
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>
返回來了同一個實例藕届,不管用alloc init創(chuàng)建還是直接用sharedInstance這個方法挪蹭。
這樣的創(chuàng)建方法,比我們文中提到的常用創(chuàng)建的單例方法更完善翰舌。
[end]