iOS设计模式(02):单例模式
分享到:QQ空間新浪微博騰訊微博微信
單例模式是一個(gè)類在系統(tǒng)中只有一個(gè)實(shí)例對象。通過全局的一個(gè)入口點(diǎn)對這個(gè)實(shí)例對象進(jìn)行訪問。在iOS開發(fā)中,單例模式是非常有用的一種設(shè)計(jì)模式。如下圖,是一個(gè)簡單的例模式的UML類圖。
“”什么是單例模式?
單例模式是一個(gè)類在系統(tǒng)中只有一個(gè)實(shí)例對象。通過全局的一個(gè)入口點(diǎn)對這個(gè)實(shí)例對象進(jìn)行訪問。在iOS開發(fā)中,單例模式是非常有用的一種設(shè)計(jì)模式。如下圖,是一個(gè)簡單的例模式的UML類圖。
?iOS SDK中也有許多類使用了單例模式,例如,UIApplication:當(dāng)程序啟動的時(shí)候,會調(diào)用UIApplicationMain方法,在該方法中,會實(shí)例化一個(gè)UIApplication對象,之后在程序中的任意地方調(diào)用sharedApplication方法都將返回一個(gè)與當(dāng)前應(yīng)用程序相關(guān)的UIApplication實(shí)例(UIApplicationMain方法中創(chuàng)建的UIApplication單例)。
?
什么時(shí)候使用單例模式?
在程序中,單例模式經(jīng)常用于只希望一個(gè)類只有一個(gè)實(shí)例,而不運(yùn)行一個(gè)類還有兩個(gè)以上的實(shí)例。當(dāng)然,在iOS SDK中,根據(jù)特定的需求,有些類不僅提供了單例訪問的接口,還為開發(fā)者提供了實(shí)例化一個(gè)新的對象接口,例如,NSFileManager可以通過defaultManager方法返回相同的一個(gè)NSFileManager對象。如果需要新的一個(gè)NSFileManager實(shí)例對象,可以通過init方法。
?
iOS中單例模式的實(shí)現(xiàn)
iOS中單例模式的實(shí)現(xiàn)方式一般分為兩種:Non-ARC(非ARC)和ARC+GCD。
1.Non-ARC(非ARC)
非ARC的實(shí)現(xiàn)方法如下所示:
BVNonARCSingleton.h
1.//
2.//? BVNonARCSingleton.h
3.//? SingletonPattern
4.//
5.//? Created by BeyondVincent on 13-5-9.
6.//? Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8.?
9.#import <Foundation/Foundation.h>
10.?
11.@interface BVNonARCSingleton : NSObject
12.?
13.@property? ( nonatomic, retain) NSString? *tempProperty;
14.+ (BVNonARCSingleton *)sharedInstance;?
15.?
16.@end11.@implementation BVNonARCSingleton
12.?
13.static BVNonARCSingleton *sharedInstance = nil;
14.?
15.// 獲取一個(gè)sharedInstance實(shí)例,如果有必要的話,實(shí)例化一個(gè)
16.+ (BVNonARCSingleton *)sharedInstance {
17.??? if (sharedInstance == nil) {
18.??????? sharedInstance = [[super allocWithZone:NULL] init];
19.??? }
20.?
21.??? return sharedInstance;
22.}
23.?
24.// 當(dāng)?shù)谝淮问褂眠@個(gè)單例時(shí),會調(diào)用這個(gè)init方法。
25.- (id)init
26.{
27.??? self = [super init];
28.?
29.??? if (self) {
30.??????? // 通常在這里做一些相關(guān)的初始化任務(wù)
31.??? }
32.?
33.??? return self;
34.}
35.?
36.// 這個(gè)dealloc方法永遠(yuǎn)都不會被調(diào)用--因?yàn)樵诔绦虻纳芷趦?nèi)容,該單例一直都存在。(所以該方法可以不用實(shí)現(xiàn))
37.-(void)dealloc
38.{
39.??? [super dealloc];
40.}
41.?
42.// 通過返回當(dāng)前的sharedInstance實(shí)例,就能防止實(shí)例化一個(gè)新的對象。
43.+ (id)allocWithZone:(NSZone*)zone {
44.??? return [[self sharedInstance] retain];
45.}
46.?
47.// 同樣,不希望生成單例的多個(gè)拷貝。
48.- (id)copyWithZone:(NSZone *)zone {
49.??? return self;
50.}
51.?
52.// 什么也不做——該單例并不需要一個(gè)引用計(jì)數(shù)(retain counter)
53.- (id)retain {
54.??? return self;
55.}
56.?
57.// 替換掉引用計(jì)數(shù)——這樣就永遠(yuǎn)都不會release這個(gè)單例。
58.- (NSUInteger)retainCount {
59.??? return NSUIntegerMax;
60.}
61.?
62.// 該方法是空的——不希望用戶release掉這個(gè)對象。
63.- (oneway void)release {
64.?
65.}
66.?
67.//除了返回單例外,什么也不做。
68.- (id)autorelease {
69.??? return self;
70.}
71.?
72.@end2.@synchronized (self)
3.{
4.??? if(sharedInstance == nil)
5.??? {
6.??????? sharedInstance = [[super allocWithZone:NULL] init];
7.??? }
8.}11.@interface BVARCSingleton : NSObject
12.?
13.@property? ( nonatomic, weak) NSString? *tempProperty;
14.+ (BVARCSingleton *)sharedInstance;
15.?
16.@end11.@implementation BVARCSingleton
12.?
13.+ (BVARCSingleton *) sharedInstance
14.{
15.??? static? BVARCSingleton *sharedInstance = nil ;
16.??? static? dispatch_once_t onceToken;? // 鎖
17.??? dispatch_once (& onceToken, ^ {???? // 最多調(diào)用一次
18.??????? sharedInstance = [[self? alloc] init];
19.??? });
20.??? return? sharedInstance;
21.}
22.?
23.// 當(dāng)?shù)谝淮问褂眠@個(gè)單例時(shí),會調(diào)用這個(gè)init方法。
24.- (id)init
25.{
26.??? self = [super init];
27.?
28.??? if (self) {
29.??????? // 通常在這里做一些相關(guān)的初始化任務(wù)
30.??? }
31.?
32.??? return self;
33.}
34.?
35.@end2.@synchronized (self)
BVNonARCSingleton.m
1.//
2.//? BVNonARCSingleton.m
3.//? SingletonPattern
4.//
5.//? Created by BeyondVincent on 13-5-9.
6.//? Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8.?
9.#import "BVNonARCSingleton.h"
10.?
?
實(shí)際上上面的代碼蘋果官網(wǎng)也有提供:Creating a Singleton Instance,只不過沒有給出頭文件的定義。上面用非ARC實(shí)現(xiàn)單例的方法是線程不安全的,如果有多個(gè)線程同時(shí)調(diào)用sharedInstance方法獲取一個(gè)實(shí)例,而sharedInstance方法需要花費(fèi)1-2秒鐘的時(shí)間,那么BVNonARCSingleton的init方法就可能會被多次調(diào)用,也就是不同線程獲得的BVNonARCSingleton有可能不是同一個(gè)實(shí)例。怎么解決線程的不安全呢?答案是使用@synchronized來創(chuàng)建互斥鎖即可。
1.// 保證在實(shí)例化的時(shí)候是線程安全的(當(dāng)然,該方法不能保證該單例中所有方法的調(diào)用都是線程安全的)
2.@synchronized (self)
3.{
4.??? if(sharedInstance == nil)
5.??? {
6.??????? sharedInstance = [[super allocWithZone:NULL] init];
7.??? }
8.}
?
通過上面的代碼就能保存線程安全。
1.<span style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;">提醒:在iOS中,一般不建議使用非ARC來實(shí)現(xiàn)單例模式。更好的方法是使用ARC+GCD來實(shí)現(xiàn)。</span>
?
2.ARC+GCD
通過ARC+GCD的方法來實(shí)現(xiàn)單例模式的非常簡單的。下面先來看看具體實(shí)現(xiàn):
BVARCSingleton.h
1.//
2.//? BVARCSingleton.h
3.//? SingletonPattern
4.//
5.//? Created by BeyondVincent on 13-5-9.
6.//? Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8.?
9.#import <Foundation/Foundation.h>
10.?
?
BVARCSingleton.m
1.//
2.//? BVARCSingleton.m
3.//? SingletonPattern
4.//
5.//? Created by BeyondVincent on 13-5-9.
6.//? Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8.?
9.#import "BVARCSingleton.h"
10.?
?
在上面的代碼中,調(diào)用Grand Central Dispatch (GCD)中的dispatch_once方法就可以確保BVARCSingleton只被實(shí)例化一次。并且該方法是線程安全的,我們不用擔(dān)心在不同的線程中,會獲得不同的實(shí)例。(當(dāng)然,該方法同樣不能保證該單例中所有方法的調(diào)用都是線程安全的)。
?
當(dāng)然,在ARC中,不用GCD也是可以做到線程安全的,跟之前非ARC代碼中使用@synchronized一樣,如下代碼:
1.??? // 不使用GCD,通過@synchronized
2.@synchronized (self)
3.{
4.??? if(sharedInstance == nil)
5.??? {
6.??????? sharedInstance = [[self alloc] init];
7.??? }
8.}
?
為了簡化使用ARC+GCD來創(chuàng)建單例,可以定義下面這樣的一個(gè)宏:
1.#define DEFINE_SHARED_INSTANCE_USING_BLOCK(block) \
2.static dispatch_once_t onceToken = 0; \
3.__strong static id sharedInstance = nil; \
4.dispatch_once(&onceToken, ^{ \
5.sharedInstance = block(); \
6.}); \
7.return sharedInstance; \
實(shí)例化的實(shí)現(xiàn)方法如下所示:
1.+ (BVARCSingleton *) sharedInstance
2.{
3.??? DEFINE_SHARED_INSTANCE_USING_BLOCK(^{
4.??????? return [[self alloc] init];
5.??? });
6.}
單例的使用
單例的使用方法很簡單,在代碼中的任意位置,如下使用即可:
在BVAppDelegate.m中添加頭文件:
1.#import "BVNonARCSingleton.h"
2.#import "BVARCSingleton.h"
如下使用方法:
1.- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
2.{
3.??? [BVNonARCSingleton sharedInstance].tempProperty = @"非ARC單例的實(shí)現(xiàn)";
4.??? NSLog(@"%@", [BVNonARCSingleton sharedInstance].tempProperty);
5.?
6.??? [BVARCSingleton sharedInstance].tempProperty = @"ARC單例的實(shí)現(xiàn)";
7.??? NSLog(@"%@", [BVARCSingleton sharedInstance].tempProperty);
8.?
9.??? return YES;
10.}
運(yùn)行程序,會在控制臺窗口輸出如下內(nèi)容:
1.2013-05-09 16:44:07.649 SingletonPattern[5159:c07] 非ARC單例的實(shí)現(xiàn)
2.2013-05-09 16:44:33.204 SingletonPattern[5159:c07] ARC單例的實(shí)現(xiàn)
代碼實(shí)例
本文涉及到的相關(guān)實(shí)例代碼和PDF歸檔可以到點(diǎn)擊下圖下載:
? ? ? ? ? ??
本文在寫作的時(shí)候,參考了許多網(wǎng)上的優(yōu)秀文章,包括如下:
What Is the Singleton Pattern?(Pro Objective-C Design Patterns for iOS書中對單例模式的介紹)
ios-patterns-singleton(需FQ,是俄文的)
Singletons in Objective-C
Implementing a Singleton in Objective-C / iOS
Grand Central Dispatch (GCD) Reference(dispatch_once的介紹)
使用GCD(來自唐巧的一篇文章,對GCD總結(jié)不錯)
Threading Programming Guide(@synchronized關(guān)鍵字的介紹)
Cocoa Fundamentals Guide(蘋果官方給的一個(gè)非ARC單例實(shí)現(xiàn))
轉(zhuǎn)載于:https://www.cnblogs.com/zsw-1993/archive/2013/05/11/4880091.html
總結(jié)
以上是生活随笔為你收集整理的iOS设计模式(02):单例模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: asp.net中关于点击页面一个控件,弹
- 下一篇: jQ.Mobi框架介绍