最近寫接口。因為比較懶。我就MJExtension直接初始化單例界酒。結(jié)果發(fā)現(xiàn)里面的值是nil.
這個單利是直接copy他們代碼過來的。懶得搞了嘴秸。催的又比較急毁欣。
代碼是這樣的:
@implementation UserCenter
+ (instancetype) getInstance
{
static dispatch_once_t once ;
static id instance = nil;
dispatch_once(&once, ^{
instance = [[[self class] alloc]init];
});
return instance;
}
他的兩個屬性也是單利庇谆。也是這樣創(chuàng)建單利的。
結(jié)果發(fā)現(xiàn)里面的基本屬性全是nil.
我的當(dāng)時懵逼了凭疮。MJExtension饭耳,用了這么久難道出毛病了不成。
[self.action postStoreInformationFirstStepWithParameter:dict finish:^(id _Nullable responseObject, NSString * _Nullable error) {
[weakSelf hideLoadingViewInSelf];
if (error) {
[weakSelf reminderUserInfo:error];
}else
{
[UserCenter mj_objectWithKeyValues:responseObject];
[[UserCenter getInstance] saveData];
MakeStoreInformationSecondStepVC *vc = [[MakeStoreInformationSecondStepVC alloc] init];
[weakSelf.navigationController pushViewController:vc animated:YES];
}
}];
網(wǎng)絡(luò)請求回來的數(shù)據(jù)responseObject是有數(shù)據(jù)的执解。但是我再次調(diào)用[UserCenter getInstance]里面的 屬性發(fā)現(xiàn)還是nil.
查看MJExtension的mj_objectWithKeyValues面的代碼:
+ (instancetype)mj_objectWithKeyValues:(id)keyValues
{
return [self mj_objectWithKeyValues:keyValues context:nil];
}
+ (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
{
// 獲得JSON對象
keyValues = [keyValues mj_JSONObject];
MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], nil, [self class], @"keyValues參數(shù)不是一個字典");
if ([self isSubclassOfClass:[NSManagedObject class]] && context) {
return [[NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(self) inManagedObjectContext:context] mj_setKeyValues:keyValues context:context];
}
return [[[self alloc] init] mj_setKeyValues:keyValues];
}
最后發(fā)現(xiàn)創(chuàng)建對象明顯是return [[[self alloc] init] mj_setKeyValues:keyValues];寞肖。看了一下沒毛病啊衰腌。
于是我在多次在控制臺打印 [[UserCenter alloc] init];
最后發(fā)現(xiàn)
很明顯多次內(nèi)存地址都不一樣新蟆,明顯不是同一個對象。
也就是這不是一個“純”單利右蕊。于是乎我改了下
static UserCenter *userZone = nil;
@implementation UserCenter
+ (instancetype) getInstance
{
static dispatch_once_t once ;
static id instance = nil;
dispatch_once(&once, ^{
instance = [[self alloc]init];
});
return instance;
}
+(id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
userZone = [super allocWithZone:zone];
});
return userZone;
}
-(id)mutableCopyWithZone:(NSZone *)zone
{
return userZone;
}
-(id)copyWithZone:(NSZone *)zone
{
return userZone;
}
這樣即使你調(diào)了copy ,mutableCopy他還是一個單利琼稻。
因為alloc 方式內(nèi)部是調(diào)allocWithZone的。上面可以直接改為
+ (instancetype) getInstance
{
static dispatch_once_t once ;
static id instance = nil;
dispatch_once(&once, ^{
instance = [[self allocWithZone:NULL]init];
});
return instance;
}
或者
+ (instancetype) getInstance
{
return [[self alloc] init];
}
+(id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
userZone = [super allocWithZone:zone];
});
return userZone;
}
-(id)mutableCopyWithZone:(NSZone *)zone
{
return userZone;
}
-(id)copyWithZone:(NSZone *)zone
{
return userZone;
}
原來的也是的對的饶囚,也允許帕翻,別人去創(chuàng)建一個新的這樣的類的對象做其他用途吧。但是要創(chuàng)建單例的時候一定要這個方法去返回萝风。
對了嘀掸,上面說alloc 回調(diào)allocWithZone:。
證實下:跟進(jìn)去看看
繼續(xù)跟進(jìn)去
下面果然調(diào)了allocWithZone:规惰。
好了睬塌,我們看看allocWithZone:里面怎么搞的:
allocWithZone:里面調(diào)的是class_createInstance.此方法是MRC方法,看光官方解釋:
ARC不可用歇万。成功就返回揩晴,失敗就到badAllocHander里面。
好了堕花,一個方法打印一下文狱,他們創(chuàng)建的對象
。果然用class_createInstance創(chuàng)建出新對象了缘挽。