面試題引發(fā)的思考:
Q: 介紹單例及其用途鬼廓?
- 單例模式保證系統(tǒng)中 一個類 只有 一個實例 而且該實例 易于外界訪問援所。
- 只初始化一次蝙云,生命周期 和 程序的生命周期 相同酸员,訪問方便;
- 主要用來封裝網(wǎng)絡(luò)請求河胎、播放器闯袒、存放常用數(shù)據(jù)等。
Q: 單例正確寫法游岳?
- OC正確寫法如下:
// TODO: ----------------- Singleton類 -----------------
@interface Singleton : NSObject <NSCopying, NSMutableCopying>
+ (instancetype)sharedInstance;
- (void)justdoit;
@end
@implementation Singleton
// 初始化方法dispatch_once政敢,本身是線程安全的,保證整個程序中只會執(zhí)行一次
+ (instancetype)sharedInstance {
static Singleton *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[super allocWithZone:nil] init];
});
return instance;
}
// 重寫 allocWithZone
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
return [Singleton sharedInstance];
}
// 遵從NSCopying協(xié)議胚迫,可通過copy方式創(chuàng)建對象
- (id)copyWithZone:(NSZone *)zone {
return self;
}
// 遵從NSMutableCopying協(xié)議堕仔,可通過mutableCopy方式創(chuàng)建對象
- (id)mutableCopyWithZone:(NSZone *)zone {
return self;
}
// 實例方法
- (void)justdoit {
NSLog(@"just do it");
}
@end
- Swift正確寫法如下:
// TODO: ----------------- Singleton類 -----------------
class Singleton {
static let shared = Singleton()
// 私有化構(gòu)造器
private init() { }
// 方法
func justdoit() {
print("just do it")
}
}
1. 單例
(1) 單例模式
單例模式保證系統(tǒng)中 一個類 只有 一個實例 而且該實例 易于外界訪問。
- 只初始化一次晌区,生命周期 和 程序的生命周期 相同摩骨,訪問方便;
- 主要用來封裝網(wǎng)絡(luò)請求朗若、播放器恼五、存放常用數(shù)據(jù)等。
經(jīng)常見到的一些系統(tǒng)單例:
[UIApplication sharedApplication]
:應(yīng)用程序
[NSNotificationCenter defaultCenter]
:通知
[NSUserDefaults standardUserDefaults]
:本地化存儲
[NSFileManager defaultManager]
:文件操作
(2) 單例寫法
蘋果官方推薦寫法:
// TODO: ----------------- Singleton類 -----------------
@interface Singleton : NSObject
+ (instancetype)sharedInstance;
- (void)justdoit;
@end
@implementation Singleton
+ (instancetype)sharedInstance {
// 聲明一個 空的靜態(tài)的 單例對象
static Singleton *instance = nil;
// 聲明一個 靜態(tài)的 gcd的單次任務(wù)
static dispatch_once_t onceToken;
// 執(zhí)行g(shù)cd單次任務(wù)
dispatch_once(&onceToken, ^{
// 對對象進行初始化
instance = [[Singleton alloc] init];
});
return instance;
}
- (void)justdoit {
NSLog(@"just do it");
}
@end
通過[Singleton sharedInstance]
創(chuàng)建對象哭懈,即可調(diào)用相關(guān)方法:
// TODO: ----------------- ViewController類 -----------------
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
/// 創(chuàng)建單例
Singleton *singleton = [Singleton sharedInstance];
[singleton justdoit];
}
@end
// 打印結(jié)果
Demo[1234:567890] just do it
(3) 以上寫法問題
如果不通過[Singleton sharedInstance]
創(chuàng)建對象灾馒,而是通過alloc
或者new
創(chuàng)建對象,會出現(xiàn)什么問題呢遣总?
// TODO: ----------------- ViewController類 -----------------
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
/// 通過不同方式創(chuàng)建對象
Singleton *singletonA= [Singleton sharedInstance];
Singleton *singletonB= [Singleton sharedInstance];
Singleton *singletonC = [[Singleton alloc] init];
Singleton *singletonD = [Singleton new];
NSLog(@"singletonA - %@", singletonA);
NSLog(@"singletonB - %@", singletonB);
NSLog(@"singletonC - %@", singletonC);
NSLog(@"singletonD - %@", singletonD);
}
@end
// 打印結(jié)果
Demo[1234:567890] singletonA - <Singleton: 0x283d35290>
Demo[1234:567890] singletonB - <Singleton: 0x283d35290>
Demo[1234:567890] singletonC - <Singleton: 0x283d352a0>
Demo[1234:567890] singletonD - <Singleton: 0x283d352b0>
由以上結(jié)果可知:
實例對象singletonA
和singletonB
的地址值是相同的睬罗;而此兩者與實例對象singletonC
和singletonD
的地址值是不同的轨功。
說明此情況下:
通過[Singleton sharedInstance]
只會創(chuàng)建一次對象;而通過alloc
或者new
會創(chuàng)建新的對象容达。
因為單例模式保證系統(tǒng)中一個類只有一個實例古涧,所以以上單例的寫法不夠嚴謹,會出現(xiàn)問題花盐。
2. 單例的正確寫法
(1) 正確寫法一
在創(chuàng)建對象的時候羡滑,alloc
或者new
都會調(diào)用到allocWithZone:
方法,需要重寫 allocWithZone:
方法算芯。
如果調(diào)用了copy
或mutableCopy
方法就會導(dǎo)致程序運行崩潰柒昏,需要實現(xiàn)copy
或mutableCopy
就要遵循協(xié)議實現(xiàn)方法。
// TODO: ----------------- Singleton類 -----------------
@interface Singleton : NSObject <NSCopying, NSMutableCopying>
+ (instancetype)sharedInstance;
- (void)justdoit;
@end
@implementation Singleton
// 初始化方法dispatch_once熙揍,本身是線程安全的职祷,保證整個程序中只會執(zhí)行一次
+ (instancetype)sharedInstance {
static Singleton *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[super allocWithZone:nil] init];
});
return instance;
}
// 重寫 allocWithZone
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
return [Singleton sharedInstance];
}
// 遵從NSCopying協(xié)議,可通過copy方式創(chuàng)建對象
- (id)copyWithZone:(NSZone *)zone {
return self;
}
// 遵從NSMutableCopying協(xié)議届囚,可通過mutableCopy方式創(chuàng)建對象
- (id)mutableCopyWithZone:(NSZone *)zone {
return self;
}
// 實例方法
- (void)justdoit {
NSLog(@"just do it");
}
@end
通過各種方式創(chuàng)建對象有梆,查看打印結(jié)果:
// TODO: ----------------- ViewController類 -----------------
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
Singleton *singletonA= [Singleton sharedInstance];
Singleton *singletonB= [Singleton sharedInstance];
Singleton *singletonC = [[Singleton alloc] init];
Singleton *singletonD = [Singleton new];
Singleton *singletonE = [singletonA copy];
Singleton *singletonF = [singletonC mutableCopy];
NSLog(@"singletonA - %@", singletonA);
NSLog(@"singletonB - %@", singletonB);
NSLog(@"singletonC - %@", singletonC);
NSLog(@"singletonD - %@", singletonD);
NSLog(@"singletonE - %@", singletonE);
NSLog(@"singletonF - %@", singletonF);
}
@end
// 打印結(jié)果
Demo[1234:567890] singletonA - <Singleton: 0x2815b9310>
Demo[1234:567890] singletonB - <Singleton: 0x2815b9310>
Demo[1234:567890] singletonC - <Singleton: 0x2815b9310>
Demo[1234:567890] singletonD - <Singleton: 0x2815b9310>
Demo[1234:567890] singletonE - <Singleton: 0x2815b9310>
Demo[1234:567890] singletonF - <Singleton: 0x2815b9310>
由打印結(jié)果可知:
實例對象singletonA
~singletonF
的地址值是相同的。
說明此情況下:
通過各種方式創(chuàng)建對象奖亚,而對象只會創(chuàng)建一次,符合單例模式定義析砸。
(2) 正確寫法二
設(shè)置只能通過[Singleton sharedInstance]
創(chuàng)建對象昔字,直接禁用alloc
、new
首繁、copy
作郭、mutableCopy
等方法即可:
// TODO: ----------------- Singleton類 -----------------
@interface Singleton : NSObject
+ (instancetype)sharedInstance;
- (void)justdoit;
+ (instancetype)alloc NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)copy NS_UNAVAILABLE;
- (instancetype)mutableCopy NS_UNAVAILABLE;
@end
@implementation Singleton
+ (instancetype)sharedInstance {
static Singleton *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[Singleton alloc] init];
});
return instance;
}
- (void)justdoit {
NSLog(@"just do it");
}
@end
此時無法通過alloc
、new
弦疮、copy
夹攒、mutableCopy
等方法創(chuàng)建對象,調(diào)用會報錯:
(3) Swift單例正確寫法
Swift中創(chuàng)建單例很方便:
// TODO: ----------------- Singleton類 -----------------
class Singleton {
static let shared = Singleton()
// 私有化構(gòu)造器
private init() { }
func justdoit() {
print("just do it")
}
}
// TODO: ----------------- ViewController類 -----------------
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any setup after loading the view.
let singleton = Singleton.shared
singleton.justdoit()
}
}