在做zon项目中,单例都是:
@implementation AppShareDataManager static AppShareDataManager * shareDataManager = nil; @synthesize theCurrentLanguage; @synthesize presentModalFlag; .......... +(AppShareDataManager *) sharedManager { if( shareDataManager == nil ) { shareDataManager = [ [ AppShareDataManager alloc ] init ]; } return shareDataManager; } -(id)init{ self = [super init]; if(self){ //对象实例初始化 theCurrentLanguage = [ZONUserDefaultManager getAppDefaultLanguage]; ........ } return self; }
调试发现
AppShareDataManager *A = [[AppShareDataManager alloc] init];
NSLog(@"A:%@",A);
AppShareDataManager *B = [AppShareDataManager sharedManager];
NSLog(@"B:%@",B);
打印出的是
2013-02-28 23:27:25.368 ZON2012[10647:c07] A:<AppShareDataManager: 0x12638630>
2013-02-28 23:27:25.369 ZON2012[10647:c07] B:<AppShareDataManager: 0xb584b40>
不是一个内存地址,也就是不是同一个实体!
这是apple官方的一个单例建议:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32
大致如下:
/* 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实现,中规中矩。不过这种实现并不是线程安全的。所以各路大神都各显神威,给出了多种单例模式的实现。
现在把他加强下:
static MyClass *class = nil;
@implementation MyClass
+(MyClass *)sharedMyClass{
@synchronized(self){ //为了确保多线程情况下,仍然确保实体的唯一性
if (!class) {
[[self alloc] init]; //该方法会调用 allocWithZone
}
}
return class;
}
+(id)allocWithZone:(NSZone *)zone{
@synchronized(self){// //为了确保多线程情况下,仍然确保实体的唯一性
if (!class) {
class = [super allocWithZone:zone]; //确保使用同一块内存地址
return class;
}
}
return nil;
}
-(id)init
{
if(class){
return class;
}
if(self = [super init]){
//进行一些初始化
}
return self ;
}
- (id)copyWithZone:(NSZone *)zone;{
return self; //确保copy对象也是唯一
}
-(id)retain{
return self; //确保计数唯一
}
- (unsigned)retainCount
{
return UINT_MAX; //装逼用的,这样打印出来的计数永远为-1
}
- (id)autorelease
{
return self;//确保计数唯一
}
- (oneway void)release
{
//重写计数释放方法 do nothing
}
@end
再调试
MyClass *A = [[MyClass alloc] init];
NSLog(@"A:%@",A);
MyClass *B = [MyClass sharedMyClass];
NSLog(@"B:%@",B);
MyClass *C = [A copy];
NSLog(@"C:%@",C);
打印出的是
A:<MyClass: 0x6a1e130>
B:<MyClass: 0x6a1e130>
C:<MyClass: 0x6a1e130>
都是指向同一块内存地址
-----------------------------------切糕分割线--------------------------------------------------------
然而这个人(http://eschatologist.net/blog/?p=178)觉的繁琐,所以给出如下实现:
@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
-----------------------------------切糕分割线--------------------------------------------------------
自苹果引入了Grand Central Dispatch (GCD)(Mac OS 10.6和iOS4.0)后,利用GCD(Grand Central Dispatch)和ARC(Automatic Reference Counting)实现单例。
+(SchoolManager *)sharedInstance
{
__strong static SchoolManager *sharedManager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[SchoolManager alloc] init];
});
return sharedManager;
}
函数void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);其中第一个参数predicate,该参数是检查后面第二个参数所代表的代码块是否被调用的谓词,第二个参数则是在整个应用程序中只会被调用一次的代码块。dispach_once函数中的代码块只会被执行一次,而且还是线程安全的。
看到如下一篇文章,用宏实现(https://gist.github.com/lukeredpath/1057420):
ExampleClass.m
GCDSingleton.h