單例模式在iOS開發中可能算是最常用的模式之一了,但是由於oc本身的語言特性,想要寫一個正確的單例模式相對來說比較麻煩,這裏我就拋磚引玉來聊一聊iOS中單例模式的設計思路。關於單例模式更多的介紹請參考這篇文章。
單例顧名思義就是說一個類的實例只能有一個,在java、C++這類語言中,可以通過將構造函數私有化來避免對象的重複創建,但是objective-c卻不能夠這樣做,我們需要通過其他機制來達到這個目的。一般情況下,可能我們寫的單例模式是這樣的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
# import
<foundation foundation.h= "" > @interface
Singleton : NSObject +(instancetype)
shareInstance ; @end # import
"Singleton.h" @implementation
Singleton static
Singleton* _instance = nil; +(instancetype)
shareInstance { static
dispatch_once_t onceToken ; dispatch_once(&onceToken,
^{ _instance
= [[self alloc] init] ; })
; return
_instance ; } @end </foundation> |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# import
<foundation foundation.h= "" > # import
"Singleton.h" int
main( int
argc, const
char
* argv[]) { @autoreleasepool
{ Singleton*
obj1 = [Singleton shareInstance] ; NSLog(@ "obj1
= %@." ,
obj1) ; Singleton*
obj2 = [Singleton shareInstance] ; NSLog(@ "obj2
= %@." ,
obj2) ; // Singleton*
obj3 = [[Singleton alloc] init] ; NSLog(@ "obj3
= %@." ,
obj3) ; } return
0 ; }</foundation> |
輸出結果爲 :
1
2
3
|
2014 - 12 - 15
16 : 06 : 28.344
ObjcSingleton[ 8847 : 303 ]
obj1 = <singleton: 0x1001086e0 = "" >. 2014 - 12 - 15
16 : 06 : 28.346
ObjcSingleton[ 8847 : 303 ]
obj2 = <singleton: 0x1001086e0 = "" >. 2014 - 12 - 15
16 : 06 : 28.346
ObjcSingleton[ 8847 : 303 ]
obj3 = <singleton: 0x100103940 = "" >.</singleton:></singleton:></singleton:> |
那麼問題就來了,我們通過不同的途徑得到不同的對象,顯然是不行的。我們必須要確保對象的唯一性,所以我們就需要封鎖用戶通過alloc和init以及copy來構造對象這條道路。
我們知道,創建對象的步驟分爲申請內存(alloc)、初始化(init)這兩個步驟,我們要確保對象的唯一性,因此在第一步這個階段我們就要攔截它。當我們調用alloc方法時,oc內部會調用allocWithZone這個方法來申請內存,我們覆寫這個方法,然後在這個方法中調用shareInstance方法返回單例對象,這樣就可以達到我們的目的。拷貝對象也是同樣的原理,覆寫copyWithZone方法,然後在這個方法中調用shareInstance方法返回單例對象。看代碼吧:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
# import
"Singleton.h" @implementation
Singleton static
Singleton* _instance = nil; +(instancetype)
shareInstance { static
dispatch_once_t onceToken ; dispatch_once(&onceToken,
^{ _instance
= [[ super
allocWithZone:NULL] init] ; })
; return
_instance ; } +(id)
allocWithZone:(struct _NSZone *)zone { return
[Singleton shareInstance] ; } -(id)
copyWithZone:(struct _NSZone *)zone { return
[Singleton shareInstance] ; } @end |
再看看效果如何:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
main
: # import
<foundation foundation.h= "" > # import
"Singleton.h" int
main( int
argc, const
char
* argv[]) { @autoreleasepool
{ Singleton*
obj1 = [Singleton shareInstance] ; NSLog(@ "obj1
= %@." ,
obj1) ; Singleton*
obj2 = [Singleton shareInstance] ; NSLog(@ "obj2
= %@." ,
obj2) ; // Singleton*
obj3 = [[Singleton alloc] init] ; NSLog(@ "obj3
= %@." ,
obj3) ; Singleton*
obj4 = [[Singleton alloc] init] ; NSLog(@ "obj4
= %@." ,
[obj4 copy]) ; } return
0 ; }</foundation> |
輸出結果:
1
2
3
4
|
2014 - 12 - 15
16 : 11 : 24.734
ObjcSingleton[ 8979 : 303 ]
obj1 = <singleton: 0x100108720 = "" >. 2014 - 12 - 15
16 : 11 : 24.735
ObjcSingleton[ 8979 : 303 ]
obj2 = <singleton: 0x100108720 = "" >. 2014 - 12 - 15
16 : 11 : 24.736
ObjcSingleton[ 8979 : 303 ]
obj3 = <singleton: 0x100108720 = "" >. 2014 - 12 - 15
16 : 11 : 24.736
ObjcSingleton[ 8979 : 303 ]
obj4 = <singleton: 0x100108720 = "" >.</singleton:></singleton:></singleton:></singleton:> |