单例模式是我在iOS开发中使用的最多的设计模式之一。它是一种不需要你去手动传递,而能在
代码的不同部分之间分享数据的一种极其强大的方式。关于单例模式和其他设计模式的更多
详情,可参考这一本不错的书:

背景

单例类是一个需要重点去理解的概念,因为它展示了一种非常有用的设计模式。这种设计思想被广泛应用在了iPhone SDK当中,例如:在代码的任何地方给UIApplication发一个叫做sharedApplication的消息都会返回同一个和当前正在运行的程序相关的UIApplicition实例。

怎么实现

可以在Objctive-C中使用如下代码来实现一个单例类:

1
2
3
4
5
6
7
8
9
10
11
#import <foundation/Foundation.h>

@interface MyManager : NSObject {
NSString *someProperty;
}

@property (nonatomic, retain) NSString *someProperty;

+ (id)sharedManager;

@end
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
28
29
#import "MyManager.h"

@implementation MyManager

@synthesize someProperty;

#pragma mark Singleton Methods

+ (id)sharedManager {
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}

- (id)init {
if (self = [super init]) {
someProperty = [[NSString alloc] initWithString:@"Default Property Value"];
}
return self;
}

- (void)dealloc {
// Should never be called, but just here for clarity really.
}

@end

上面的代码所做的是在sharedManager方法中定义一个名为sharedMyManager的静态局部变量(仅仅在这一个translation unit中是全局的),这个静态局部变量仅仅初始化一次。为了确保它只被建立一次,我们使用了Grand Central Dispatch(GCD)中的dispath_once.GCD是完全由操作系统控制的,并且是线程安全的,所以你可以毫无顾虑的去使用它.如果不愿使用GCD,可以使用以下代码来替换sharedManager

1
2
3
4
5
6
7
8
+ (id)sharedManager {
static MyManager *sharedMyManager = nil;
@synchronized(self) {
if (sharedMyManager == nil)
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}

然后,你就可以在工程的任意地方通过调用如下的函数来饮用一个单例类:

MyManager *sharedManager = [MyManager sharedManager];我已经在代码中大量使用了这样的方式,比如:创建一个单例类去控制CoreLocation或者CoreData函数

Non-ARC code

不推荐使用。但是如果你没有使用Automatic Reference Counting(ARC)的话,只能使用以下代码:

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#import "MyManager.h"

static MyManager *sharedMyManager = nil;

@implementation MyManager

@synthesize someProperty;

#pragma mark Singleton Methods
+ (id)sharedManager {
@synchronized(self) {
if(sharedMyManager == nil)
sharedMyManager = [[super allocWithZone:NULL] init];
}
return sharedMyManager;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedManager] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be released
}
- (oneway void)release {
// never release
}
- (id)autorelease {
return self;
}
- (id)init {
if (self = [super init]) {
someProperty = [[NSString alloc] initWithString:@"Default Property Value"];
}
return self;
}
- (void)dealloc {
// Should never be called, but just here for clarity really.
[someProperty release];
[super dealloc];
}

@end

原文在此