所謂單例就是確保在程序運(yùn)行過程中只創(chuàng)建一個(gè)對象實(shí)例法希,可以用于需要被多次廣泛或者說多次使用的資源中,比如我們常見的網(wǎng)絡(luò)請求類残黑、工具類、以及其他管理類斋否。在iOS開發(fā)中梨水,單例模式是非常有用的設(shè)計(jì)模式
一.iOS系統(tǒng)單例
-
NSUserDefaults
類和defaultUser
方法 -
UIApplication
類和sharedApplication
方法,我們一般使用該方法來創(chuàng)建全局變量 -
NSBundle
類和mainBundle
方法 -
NSFileManager
類和defaultManager
方法 -
NSNotificationCenter
類和DefaultManager
方法,其中NSNotificationCenter
也實(shí)現(xiàn)了觀察者模式
二. 使用單例模式的作用
它可以保證某個(gè)類在程序運(yùn)行過程中最多只有一個(gè)實(shí)例茵臭,也就是對象實(shí)例只占用一份內(nèi)存資源
119556-20151216021009693-251451918.png
三. 單例模式的三個(gè)要點(diǎn)
- 該類有且只有一個(gè)實(shí)例
- 該類必須能夠自行創(chuàng)建這個(gè)實(shí)例
- 該類必須能夠自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例
四. 為什么要使用單例
- 節(jié)省內(nèi)存開銷冰木。如果某個(gè)對象需要被多個(gè)其它對象使用,那可以考慮使用單例笼恰,因?yàn)檫@樣該類只使用一份內(nèi)存資源
- 使用單例踊沸,可以確保其它類只獲取類的一份數(shù)據(jù)(變量值)
五. 單例模式優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn)
- 提供了對唯一實(shí)例的受控訪問
- 由于在系統(tǒng)內(nèi)存中只存在一個(gè)對象,因此可以節(jié)省系統(tǒng)資源社证,對于一些需要頻繁創(chuàng)建和銷毀的對象單例模式無疑可以提高系統(tǒng)的性能
- 因?yàn)閱卫J降念惪刂屏藢?shí)例化的過程逼龟,所以類可以更加靈活修改實(shí)例化過程
- 缺點(diǎn)
- 由于單例模式中沒有抽象層,因此單例類的擴(kuò)展有很大的困難
- 單例類的職責(zé)過重追葡,在一定程度上違背了"單一職責(zé)原則"
六.單例的實(shí)現(xiàn)
- 基本步驟
1. 為單例對象創(chuàng)建一個(gè)靜態(tài)實(shí)例腺律,可以寫成全局的奕短,也可以在類方法里面實(shí)現(xiàn),并初始化為nil
2. 實(shí)現(xiàn)一個(gè)實(shí)例構(gòu)造方法匀钧,檢查上面聲明的靜態(tài)實(shí)例是否為nil翎碑,如果是,則創(chuàng)建并返回一個(gè)本類的實(shí)例
3. 重寫allocWithZone方法之斯,用來保證其他人直接使用alloc和init試圖獲得一個(gè)新實(shí)例的時(shí)候不產(chǎn)生一個(gè)新實(shí)例
4. 適當(dāng)實(shí)現(xiàn)copyWithZone日杈,mutableCopyWithZone,非ARC下還需要實(shí)現(xiàn)release和autorelease方法
- 代碼示例
新建一個(gè)Singleton
類佑刷,在Singleton.h
中實(shí)現(xiàn)如下
//
// Singleton.h
// TestSingleton
//
// Created by taobaichi on 2017/4/13.
// Copyright ? 2017年 MaChao. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Singleton : NSObject
+(Singleton *)sharedInstance;
@end
在Singleton.m
添加如下代碼
//
// Singleton.m
// TestSingleton
//
// Created by taobaichi on 2017/4/13.
// Copyright ? 2017年 MaChao. All rights reserved.
//
#import "Singleton.h"
static Singleton * sharedSingleton = nil;
@implementation Singleton
+(Singleton *) sharedInstance
{
if (sharedSingleton == nil) {
sharedSingleton = [[Singleton alloc]init];
}
return sharedSingleton;
}
@end
這樣就創(chuàng)建一個(gè)簡單的單例模式莉擒,實(shí)際上有一部分程序員也是這樣實(shí)現(xiàn)的,但實(shí)際上這是一個(gè)不嚴(yán)格
的版本瘫絮,也就是一個(gè)假單例
涨冀,在實(shí)際中使用,如果我們使用alloc
麦萤,copy
等方法創(chuàng)建對象時(shí)鹿鳖,依然會創(chuàng)建新的實(shí)例,而且如果多線程同時(shí)訪問時(shí)候也會創(chuàng)建多個(gè)實(shí)例壮莹,因此這樣做是非線程安全
的栓辜。
下面對Singleton.m
進(jìn)行改進(jìn)
//
// Singleton.m
// TestSingleton
//
// Created by taobaichi on 2017/4/13.
// Copyright ? 2017年 MaChao. All rights reserved.
//
#import "Singleton.h"
static Singleton * _sharedSingleton = nil;
@implementation Singleton
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedSingleton = [super allocWithZone:zone];
});
return _sharedSingleton;
}
-(id)init
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedSingleton = [super init];
});
return _sharedSingleton;
}
+(instancetype)sharedInstance
{
return [[self alloc]init];
}
+(id)copyWithZone:(struct _NSZone *)zone
{
return _sharedSingleton;
}
+(id)mutableCopyWithZone:(struct _NSZone *)zone
{
return _sharedSingleton;
}
@end
- 測試
一. 對假單例進(jìn)行調(diào)用
單例寫法
// Singleton.m
// TestSingleton
//
// Created by taobaichi on 2017/4/13.
// Copyright ? 2017年 MaChao. All rights reserved.
//
#import "Singleton.h"
static Singleton * _sharedSingleton = nil;
@implementation Singleton
+(Singleton *)sharedInstance
{
if (_sharedSingleton == nil) {
_sharedSingleton = [[Singleton alloc]init];
}
return _sharedSingleton;
}
@end
- 調(diào)用方法一
//
// ViewController.m
// TestSingleton
//
// Created by taobaichi on 2017/4/13.
// Copyright ? 2017年 MaChao. All rights reserved.
//
#import "ViewController.h"
#import "Singleton.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self testSingleton];
}
-(void)testSingleton
{
Singleton * single1 = [Singleton sharedInstance];
Singleton * single2 = [Singleton sharedInstance];
if (single1 == single2) {
NSLog(@"single1 == single2");
}
NSLog(@"single1地址 %@",single1);
NSLog(@"single2地址 %@",single2);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
打印結(jié)果
2017-04-13 13:12:27.327 TestSingleton[2515:106202] single1 == single2
2017-04-13 13:12:27.327 TestSingleton[2515:106202] single1地址 <Singleton: 0x6000000147f0>
2017-04-13 13:12:27.327 TestSingleton[2515:106202] single2地址 <Singleton: 0x6000000147f0>
- 調(diào)用方法二:
//
// ViewController.m
// TestSingleton
//
// Created by taobaichi on 2017/4/13.
// Copyright ? 2017年 MaChao. All rights reserved.
//
#import "ViewController.h"
#import "Singleton.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self testSingleton];
}
-(void)testSingleton
{
Singleton * single1 = [[Singleton alloc]init];
Singleton * single2 = [[Singleton alloc]init];
if (single1 == single2) {
NSLog(@"single1 == single2");
}
NSLog(@"single1地址 %@",single1);
NSLog(@"single2地址 %@",single2);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
打印結(jié)果:
2017-04-13 13:13:47.526 TestSingleton[2529:108124] single1地址 <Singleton: 0x60800001cda0>
2017-04-13 13:13:47.526 TestSingleton[2529:108124] single2地址 <Singleton: 0x60800001cdb0>
可以看到,假單例當(dāng)用alloc實(shí)例化的時(shí)候垛孔,生成的并不是一個(gè)單例藕甩,也就是說并不是同一個(gè)對象
二. 對真單例無論怎么實(shí)例化生成的都是同一個(gè)對象
真單例寫法
//
// Singleton.m
// TestSingleton
//
// Created by taobaichi on 2017/4/13.
// Copyright ? 2017年 MaChao. All rights reserved.
//
#import "Singleton.h"
static Singleton * _sharedSingleton = nil;
@implementation Singleton
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedSingleton = [super allocWithZone:zone];
});
return _sharedSingleton;
}
-(id)init
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedSingleton = [super init];
});
return _sharedSingleton;
}
+(instancetype)sharedInstance
{
return [[self alloc]init];
}
+(id)copyWithZone:(struct _NSZone *)zone
{
return _sharedSingleton;
}
+(id)mutableCopyWithZone:(struct _NSZone *)zone
{
return _sharedSingleton;
}
@end
調(diào)用
//
// ViewController.m
// TestSingleton
//
// Created by taobaichi on 2017/4/13.
// Copyright ? 2017年 MaChao. All rights reserved.
//
#import "ViewController.h"
#import "Singleton.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self testSingleton];
}
-(void)testSingleton
{
Singleton * single1 = [[Singleton alloc]init];
Singleton * single2 = [[Singleton alloc]init];
if (single1 == single2) {
NSLog(@"single1 == single2");
}
NSLog(@"single1地址 %@",single1);
NSLog(@"single2地址 %@",single2);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
打印結(jié)果
2017-04-13 13:20:31.480 TestSingleton[2562:111462] single1 == single2
2017-04-13 13:20:31.481 TestSingleton[2562:111462] single1地址 <Singleton: 0x608000012b00>
2017-04-13 13:20:31.481 TestSingleton[2562:111462] single2地址 <Singleton: 0x608000012b00>