单例模式在Cocoa和Cocoa Touch中非常常见。比如这两个,[UIApplication sharedApplication]
和[NSApplication sharedApplication]
,大家应该都见过。但是我们应该如何在代码中实现一个单例模式呢?
如果你对苹果的文档很熟悉的话,你一定知道,在Cocoa Foundamentals Guide 中有一段实现单例模式的示例代码 。大致如下:
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
48
49
50
51
52
53
/* Singleton.h */
#import <Foundation/Foundation.h>
@interface Singleton : NSObject
+ ( Singleton * ) instance ;
@end
/* Singleton.m */
#import "Singleton.h"
static Singleton * instance = nil ;
@implementation Singleton
+ ( Singleton * ) instance {
if ( ! instance ) {
instance = [[ super allocWithZone : NULL ] init ];
}
return instance ;
}
+ ( id ) allocWithZone: ( NSZone * ) zone {
return [ self instance ];
}
- ( id ) copyWithZone: ( NSZone * ) zone {
return self ;
}
- ( id ) init {
if ( instance ) {
return instance ;
}
self = [ super init ];
return self ;
}
- ( id ) retain {
return self ;
}
- ( oneway void ) release {
// Do nothing
}
- ( id ) autorelease {
return self ;
}
- ( NSUInteger ) retainCount {
return NSUIntegerMax ;
}
@end
这是一种很标准的Singleton实现,中规中矩。不过这种实现并不是线程安全的。所以各路大神都各显神威,给出了多种单例模式的实现。
Matt Gallagher在博客 中放出了一个Macro,用来实现单例模式。虽然是一个宏定义的代码,但是具体实现还是很清楚的。代码如下:
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//
// SynthesizeSingleton.h
// CocoaWithLove
//
// Created by Matt Gallagher on 20/10/08.
// Copyright 2009 Matt Gallagher. All rights reserved.
//
// Permission is given to use this source code file without charge in any
// project, commercial or otherwise, entirely at your risk, with the condition
// that any redistribution (in part or whole) of source code must retain
// this copyright and permission notice. Attribution in compiled projects is
// appreciated but not required.
//
#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \
\
static classname *shared##classname = nil; \
\
+ (classname *)shared##classname \
{ \
@synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [[self alloc] init]; \
} \
} \
\
return shared##classname; \
} \
\
+ (id)allocWithZone:(NSZone *)zone \
{ \
@synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [super allocWithZone:zone]; \
return shared##classname; \
} \
} \
\
return nil; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return self; \
} \
\
- (id)retain \
{ \
return self; \
} \
\
- (NSUInteger)retainCount \
{ \
return NSUIntegerMax; \
} \
\
- (void)release \
{ \
} \
\
- (id)autorelease \
{ \
return self; \
}
然而,eschaton则觉得这些实现都太繁琐了,他给出的实现如下:
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
@interface SomeManager : NSObject
+ ( id ) sharedManager ;
@end
/* 非线程安全的实现 */
@implementation SomeManager
+ ( id ) sharedManager {
static id sharedManager = nil ;
if ( sharedManager == nil ) {
sharedManager = [[ self alloc ] init ];
}
return sharedManager ;
}
@end
/* 线程安全的实现 */
@implementation SomeManager
static id sharedManager = nil ;
+ ( void ) initialize {
if ( self == [ SomeManager class ]) {
sharedManager = [[ self alloc ] init ];
}
}
+ ( id ) sharedManager {
return sharedManager ;
}
@end
关于为什么上述代码就能实现单例模式,以及关于线程安全问题的考量,请参考他的博客 。
最后介绍一个比较现代的单例模式实现 。为什么说现代呢?因为这种实现利用了GCD(Grand Central Dispatch)和ARC(Automatic Reference Counting)。核心代码如下:
1
2
3
4
5
6
7
8
9
+ ( id ) sharedInstance
{
static dispatch_once_t pred = 0 ;
__strong static id _sharedObject = nil ;
dispatch_once ( & pred , ^ {
_sharedObject = [[ self alloc ] init ]; // or some other init method
});
return _sharedObject ;
}
作者还写了一个宏(gist )来方便使用,大家可以阅读作者的博文A note on Objective-C singletons 了解详情。
大多数情况下,Apple官方文档里的单例模式的示例代码实现已经够用了。虽然它最繁琐,但是也是本文介绍的几种单例模式中最容易理解的一个。至于其他的实现就留给读者们根据需要选择和应用了。
(全文完)