@synchronized
定义一个静态的全局的变量
static Settings *sharedSettings = nil;
创建一个类方法,用来返回该类实例
synchronized
这个主要是考虑多线程的程序,这个指令可以将{ } 内的代码限制在一个线程执行,如果某个线程没有执行完,其他的线程如果需要执行就得等着。
+ (Settings *)sharedInstance {
@synchronized(self){
if(sharedSettings == nil){
sharedSettings = [[self alloc] init];
//做一些初始化操作
}
}
return sharedSettings;
}
- 重写allocWithZone方法,用来保证其他人直接使用alloc和init试图获得一个新实力的时候不产生一个新实例,
+ (id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
if (sharedSettings == nil) {
sharedSettings = [super allocWithZone:zone];
}
}
return sharedSettings;
}
dispatch_once
有些变量只需要初始化一次(如从文件中读取配置参数,读取设备型号等等),可以使用dispatch_once来进行读取优化,保证只调用API一次,以后就只要直接访问变量即可
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
dispatch_once不仅意味着代码仅会被运行一次,而且还是线程安全的,这就意味着你不需要使用诸如
@synchronized
之类的来防止使用多个线程或者队列时不同步的问题。
//范例如下:
static BOOL isTestMode;
+ (BOOL)isTestMode {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSNumber* obj = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFResourceTest"];
isTestMode = [obj boolValue];
});
return isTestMode;
}
实际要如何使用这些呢?
好吧,假设有一个AccountManager类,你想在整个应用中访问该类的共享实例。你可以按如下代码简单实现一个类方法:
+ (AccountManager *)sharedManager {
static AccountManager *sharedAccountManagerInstance = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
sharedAccountManagerInstance = [[self alloc] init];
});
return sharedAccountManagerInstance;
}
这就意味着你任何时候访问共享实例,需要做的仅是:
AccountManager *accountManager = [AccountManager sharedManager];
该方法有很多优势 |
---|
a. 线程安全 |
b. 很好满足静态分析器要求 |
c. 和自动引用计数(ARC)兼容 |
d. 仅需要少量代码 |
就这些,你现在在应用中就有一个共享的实例,该实例只会被创建一次。
该方法有很多优势 |
---|
a. 线程安全 |
b. 很好满足静态分析器要求 |
c. 和自动引用计数(ARC)兼容 |
d. 仅需要少量代码 |
该方法的劣势就是它仍然运行创建一个非共享的实例:我们通常在OC中实现一个单例方法都是这样:
static HLTestObject *instance = nil;
+ (instancetype)sharedInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[[self class] alloc] init];
});
return instance;
}
可是这样就可以了么?我做了如下测试:
HLTestObject *objct1 = [HLTestObject sharedInstance];
NSLog(@"%@",objct1);
HLTestObject *objc2 = [[HLTestObject alloc] init];
NSLog(@"%@",objc2);
HLTestObject *objc3 = [HLTestObject new];
NSLog(@"%@",objc3);
看到这个测试,你想到打印结果了么?结果是这样的:
2016-05-23 12:52:57.095 PractiseProject[3579:81998] <hltestobject: 0x7fcf39515510>
2016-05-23 12:52:57.095 PractiseProject[3579:81998] <hltestobject: 0x7fcf395c4b70>
2016-05-23 12:52:57.095 PractiseProject[3579:81998] <hltestobject: 0x7fcf395c6890></hltestobject: 0x7fcf395c6890></hltestobject: 0x7fcf395c4b70></hltestobject: 0x7fcf39515510>
很明显,通过三种方式创建出来的是不同的实例对象,这就违背了单例类有且仅有一个实例的定义。
为了防止别人不小心利用alloc/init方式创建示例,也为了防止别人故意为之,我们要保证不管用什么方式创建都只能是同一个实例对象,这就得重写另一个方法,实现如下:
static TYGAreaPickerView *sharedObject = nil;
+ (TYGPlaceholderHelper *)sharedInstance {
static dispatch_once_t _singletonPredicate;
dispatch_once(&_singletonPredicate, ^{
sharedObject = [[super allocWithZone:nil] init];
});
return sharedObject;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
static HLTestObject *instance = nil;
+ (instancetype)sharedInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[[self class] alloc] init];
instance.height = 10;
instance.object = [[NSObject alloc] init];
instance.arrayM = [[NSMutableArray alloc] init];
});
return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
return instance;
}
static HLTestObject *instance = nil;
+ (instancetype)sharedInstance {
return [[self alloc] init];
}
- (instancetype)init {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super init];
instance.height = 10;
instance.object = [[NSObject alloc] init];
instance.arrayM = [[NSMutableArray alloc] init];
});
return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
return instance;
}