一、概念
单例的概念和JAVA中原理类似,就是在整个程序声明周期中,该对象始终只有一份保存在内存中。单例对象是全局变量,方便数据共享。
二、单例的经典写法
static id sharedMyManager;
+(id)sharedThemeManager{
if(sharedMyManager == nil){
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}
需要有一个全局的类的对象,在单例方法中,第一次调用该方法时,实例化该对象,以后每一次调用都返回该对象。多个指针指向同一内存空间。
单例的方法命名规范:
shared/default/current+类名
三、经典单例模式的一个例子
#import <Foundation/Foundation.h>
//主题管理器
@interface ThemeManager : NSObject
{
//主题名称
NSString * _name;
}
@property(nonatomic, retain)NSString * name;
//单例方法
+(id)sharedThemeManager;
@end
#import "ThemeManager.h"
//声明一个全局的该类的对象
static ThemeManager * manager;
@implementation ThemeManager
//实现setter和getter
@synthesize name = _name;
//实现单例的方法
+(id)sharedThemeManager{
if(manager == nil){
//manager = [[self alloc] init];
//只有第一次调用该方法的时候,才会创建对象的实例,并将该对象保存为全局变量,之后每一次调用该方法,都返回这个全局变量。
manager = [[[self class] alloc] init];
}
return manager;
}
-(id)init{
self = [super init];
if(self){
self.name = [NSString stringWithFormat:@"Default"];
//使用Default作为初始化的name,取代nil
}
return self;
}
-(NSString *)description{
return [NSString stringWithFormat:@"Theme name is %@", self.name];
}
-(void)dealloc{
[_name release];
_name = nil;
[super dealloc];
}
@end
#import <Foundation/Foundation.h>
#import "ThemeManager.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//使用单例创建两个对象,这里虽然使用alloc也没问题,但不建议这么做。既然是单例模式,就按照单例的规范来写
ThemeManager * tm1 = [ThemeManager sharedThemeManager];
ThemeManager * tm2 = [ThemeManager sharedThemeManager];
tm2.name = @"夏日倾情";
//使用%p输出对象的内存地址,结果是相同的,也就是两个对象指向同一内存空间。
NSLog(@"tm1 is %p, tm2 is %p", tm1, tm2);
//这里由于默认的name是nil,我们可以重写init来修改这个值
NSLog(@"tm1:%@,tm2:%@", tm1, tm2);
}
return 0;
}
四、单例模式的其他写法
1.经典单例模式的缺陷
经典单例模式,是工业级写法,但是有一个缺陷。如果有两个线程,同时调用了该单例方法,就有可能同时满足if(manager == nil)条件,创建了2个对象,造成内存泄露,是 非线程安全的。
2.加锁写法
类似java中的加锁写法
static ThemeManager * manager;
+(id)sharedThemeManager{
//加锁,锁为self
@synchronized(self) {
if(manager == nil){
manager = [[self alloc] init];
}
}
return manager;
}
3.免锁写法
//免锁写法,Lock Free
//该方法只在类的对象第一次alloc的时候调用,有且只调用一次。
+ (void)initialize
{
static BOOL initialized = NO;
if (initialized == NO) {
initialized = YES;
manager = [[self alloc] init];
}
}
4.GCD写法
+(id)sharedThemeManager{
static dispatch_once_t once;
dispatch_once(&once, ^{
manager = [[self alloc] init];
});
return manager;
}
该写法,保证了即使有多个线程,{}代码块也只执行一次。
最常用的写法:经典写法、加锁写法、GCD写法
@诗未冷学习博客