所謂單例就是確保在程序運行過程中只創(chuàng)建一個對象實例。可以用于需要被多次廣泛或者說多次使用的資源中,比如我們常見的網(wǎng)絡(luò)請求類、工具類以及其它管理類等。iOS開發(fā)中常見的系統(tǒng)單例[UIApplication sharedApplication]、[NSUserDefaults standardUserDefaults]等。
一、單例模式的三大要點:
1、某個類只能有一個實例;
2、它必須自行創(chuàng)建這個實例;
3、它必須自行向整個系統(tǒng)提供這個實例。
二、單例模式優(yōu)缺點
優(yōu)點
1、提供了對唯一實例的受控訪問。
2、由于在系統(tǒng)內(nèi)存中只存在一個對象,因此可以節(jié)約系統(tǒng)資源,對于一些需要頻繁創(chuàng)建和銷毀的對象單例模式無疑可以提高系統(tǒng)的性能。
3.因為單例模式的類控制了實例化的過程,所以類可以更加靈活修改實例化過程。
缺點
1、由于單利模式中沒有抽象層,因此單例類的擴展有很大的困難。
2、單例類的職責過重,在一定程度上違背了“單一職責原則”。
三、單例的實現(xiàn)
基本步驟:
1、 為單例對象創(chuàng)建一個靜態(tài)實例,可以寫成全局的,也可以在類方法里面實現(xiàn),并初始化為nil;
2、 實現(xiàn)一個實例構(gòu)造方法,檢查上面聲明的靜態(tài)實例是否為nil,如果是,則創(chuàng)建并返回一個本類的實例;
3、 重寫allocWithZone方法,用來保證其他人直接使用alloc和init試圖獲得一個新實力的時候不產(chǎn)生一個新實例;
4、適當實現(xiàn)copyWithZone,mutableCopyWithZone,非arc下還需要實現(xiàn)release和autorelease方法。
下面新建一個singleton類,在Singleton.h上實現(xiàn)如下:
#import <Foundation/Foundation.h>
@interface Singleton : NSObject
+(instancetype)sharedInstance;
@end
在Singleton.m上實現(xiàn)如下:
#import "Singleton.h"
//創(chuàng)建全局靜態(tài)實例
static Singleton *singleton = nil;
@implementation Singleton
//使用GCD的方式來使用單例,效果最高的
+(instancetype)sharedInstance{
//防止本方法被多次調(diào)用而引發(fā)沖突
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
//此處的代碼僅會被調(diào)用一次
singleton = [[Singleton alloc] init];
});
return singleton;
}
//如果允許另外使用alloc/new創(chuàng)建非單例對,剛不必重寫此方法
+(instancetype)allocWithZone:(struct _NSZone *)zone{
//防止本方法被多次調(diào)用而發(fā)生沖突
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//此處僅會調(diào)用一次
singleton = [super allocWithZone:zone];
});
return singleton;
}
//以下代碼僅在非ARC環(huán)境下需要
#if !__has_feature(objc_arc)
-(NSUInteger)retainCount{
//返回一個最大的整數(shù),表示此數(shù)字沒有意義
return NSInteger;
}
-(id)retain{
//直接返回自身,不改變引用計數(shù)器
return self;
}
-(oneway void)release{
//什么都不用做
}
-(id)autorelease{
//直接返回自身,不改變引用計數(shù)器
return self;
}
#endif
@end
打印看看:
Singleton *singleton = [Singleton sharedInstance];
NSLog(@"singleton= %@",singleton); //singleton = <Singleton: 0x7a74c120>
小案例:
新建一個DataManager類,在DataManager.h上實現(xiàn)如下:
#import <Foundation/Foundation.h>
@interface DataManager : NSObject
+(instancetype)shareManager;
@property (nonatomic,copy) NSString *UserName;
@property (nonatomic,copy) NSString *setNumber;
@end
在DataManager.m類上實現(xiàn)如下:
#import "DataManager.h"
#define KName @"managerName"
#define KNubmer @"managerNumber"
@interface DataManager ()
@property (nonatomic,strong)NSUserDefaults *userDefault;
@end
@implementation DataManager
@synthesize UserName = _UserName;
@synthesize setNumber = _setNumber;
//創(chuàng)建單例類
static DataManager *dataManager = nil;
+(instancetype)shareManager{
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
dataManager = [[DataManager alloc]init];
});
return dataManager;
}
//懶加載
-(NSUserDefaults *)userDefault{
if (!_userDefault) {
_userDefault = [NSUserDefaults standardUserDefaults];
}
return _userDefault;
}
//保存字符串類型的
-(void)setUserName:(NSString *)UserName{
_UserName = UserName;
[self.userDefault setObject:_UserName forKey:KName];
[self.userDefault synchronize];
}
//獲取
-(NSString *)UserName{
_UserName = [self getStringNil:[self.userDefault objectForKey:KName]];
return _UserName;
}
//保存NSInteger類型數(shù)字
-(void)setNubmer :(NSInteger) isNubmer{
_setNumber = isNubmer;
[self.userDefault setInteger:_setNumber forKey:KNubmer];
}
//取出數(shù)字
-(NSInteger)setNubmer{
_setNumber = [self.userDefault integerForKey:KNubmer] ;
return _setNumber;
}
- (NSString *)getStringNil:(NSString *)string
{
if ([string isKindOfClass:[NSNull class]] || !string ) {
string = @"";
}
string = [NSString stringWithFormat:@"%@",string];
return string;
}
@end
調(diào)用方法
//保存
[[DataManager shareManager] setUserName:@"name"];
//讀取
NSString *string = [DataManager shareManager].UserName;
NSLog(@"string = %@ ",string); //輸出string = name