ios-设计模式-单例
1)单例是一种编程思想,一个设计模式,与语言无关在采用了单例对象的应用程序中,需要单例类自行提供实例化单例对象,
不管实例化单例对象多少次,只有一个对象存在,这个对象是全局的,能够被整个应用程序共享,访问
2)使用单例模式时使用类提供的类方法获取单例对象,尽量不要用alloc init的方法获取单例对象
3)单例类提供类方法获取单例对象时类方法一般以sharedXX/standedXX/defaultXX开头
以下为翻译部分:
翻译自:http://www.galloway.me.uk/tutorials/singleton-classes/ 若有不精确之处,还望不吝赐教。
单例模式singleton pattern是经常使用的设计模式,它不用传递参数,就能在两个不同的代码块之间实现数据共享
比如:从任何地方调用UIApplication 的 sharedApplication方法,都会返回与当前运行程序相关的UIApplication实例。
如何实现单例类:(ARC)
#import <foundation/Foundation.h>
@interface MyManager : NSObject {
NSString *someProperty;
}
@property (nonatomic, retain) NSString *someProperty;
+ (id)sharedManager;
@end
#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
上面定义了静态变量sharedMyManager 在sharedManager里只被实例化一次,GCD的dispatch_once方法保证只被创建一次,并且是线程安全的。
当然,如果不想使用GCD,可以使用下面的代码:
+ (id)sharedManager {
static MyManager *sharedMyManager = nil;
@synchronized(self) {
if (sharedMyManager == nil)
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}
用下面的方法可以从任何一个地方调用这个单例
MyManager *sharedManager = [MyManager sharedManager];
单例使用广泛,比如处理CoreLocation or CoreData函数
非ARC代码:
#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
以下加入我的理解:
不知你是否在上面ARC下用如下代码测试过
MyManager *mm1 = [[MyManager alloc] init];
MyManager *mm2 = [[MyManager alloc] init];
MyManager *mm3 = [[MyManager alloc] init];
NSLog(@"\n%@\n%@\n%@",mm1,mm2,mm3);
MyManager *mm4 = [MyManager sharedManager];
MyManager *mm5 = [MyManager sharedManager];
NSLog(@"\n%@\n%@",mm4,mm5);
mm1 mm2 mm3的值(地址)是不一样的,mm4 mm5一样,重写allocWithZone就能保证mm1 mm2 mm3的值一样了。当然如果需要copy,则要重写copyWithZone
+(id)allocWithZone:(NSZone *)zone{
@synchronized(self){
if (sharedMyManager == nil) {
sharedMyManager = [super allocWithZone:zone]; //确保使用同一块内存地址
return sharedMyManager;
}
return sharedMyManager;
}
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
为什么实现allocWithZone、copyWithZone这两个方法?
创建对象的时候,alloc表示申请内存,init表示初始化,程序在alloc时,会在allocWithZone这个方法申请内存,我们只要在这个方法中调用sharedManager返回单例即可。这样就不会申请多次内存了。拷贝对象以此类推,同理所得,要重写copyWithZone。这样就保证了这个类只被实例化了一次。
@synchronized 保证线程安全
单例可以用来传值,系统UIApplication NSUserDefaults 就是单例类。
单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例