方法中的关键字self引用方法的所有者,对于实例方法是对象的实例,对于类方法是类。但是,saveContex 消息末尾缺少一个 t (saveContext)。
dispatch_once 单例
这是一个与 ARC 兼容的更好的单例习语:
+(MySingleton *)sharedInstance {
static dispatch_once_t pred;
static MySingleton *shared = nil;
dispatch_once(&pred, ^{
shared = [[MySingleton alloc] init];
});
return shared;
}
与 Xcode 模板相同的代码
与带有占位符的 Xcode 模板相同的代码:
+ (<#class#> *)shared<#name#> {
static dispatch_once_t onceToken;
static <#class#> *shared<#name#> = nil;
dispatch_once(&onceToken, ^{
shared<#name#> = <#initializer#>;
});
return shared<#name#>;
}
相同的代码 + 禁用 alloc/init/new
想要提示用户他们应该调用sharedInstance 而不是alloc/init/new?您可以禁用属性不可用的方法。如果在类上调用这些方法中的任何一个,这将导致编译器错误。
#import <Foundation/Foundation.h>
@interface MySingleton : NSObject
+(instancetype) sharedInstance;
// clue for improper use (produces compile time error)
+(instancetype) alloc __attribute__((unavailable("alloc not available, call sharedInstance instead")));
-(instancetype) init __attribute__((unavailable("init not available, call sharedInstance instead")));
+(instancetype) new __attribute__((unavailable("new not available, call sharedInstance instead")));
@end
#import "MySingleton.h"
@implementation MySingleton
+(instancetype) sharedInstance {
static dispatch_once_t pred;
static id shared = nil;
dispatch_once(&pred, ^{
shared = [[super alloc] initUniqueInstance];
});
return shared;
}
-(instancetype) initUniqueInstance {
return [super init];
}
@end
警告:dispatch_once 不可重入
不要从dispatch_once 块内递归调用sharedInstance。
如果您从多个线程调用dispatch_once,它将充当阻止并发访问的屏障。 但是如果你在块内部的同一个线程中再次调用它,它会死锁线程。这个例子说明了这个问题:
#import <Foundation/Foundation.h>
static NSRecursiveLock *_lock = nil;
// constructor = run before main. used = emit code even if the function is not referenced.
// See http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
static void runBeforeMain(void) __attribute__ ((constructor, used));
static void runBeforeMain(void) {
_lock = [NSRecursiveLock new];
}
static void test(void)
{
static NSUInteger count = 0;
NSLog(@"iteration #%lu", ++count);
// WRONG: deadlock!
//static dispatch_once_t token;
//dispatch_once(&token, ^{
// test();
//});
// OK
[_lock lock];
test();
[_lock unlock];
--count;
}
int main(int argc, char **argv) {
@autoreleasepool {
test();
}
return EXIT_SUCCESS;
}
+初始化单例
使用+initialize 是另一种创建单例的惯用语。优点:它比dispatch_once 快几倍。缺点:+initialize 每个类调用一次,因此如果您将单例子类化,也会为每个父类创建一个实例。仅当您知道单例不会被子类化时才使用它。
static id sharedInstance;
+ (void) initialize {
// subclassing would result in an instance per class, probably not what we want
NSAssert([MySingleton class] == self, @"Subclassing is not welcome");
sharedInstance = [[super alloc] initUniqueInstance];
}
+(instancetype) sharedInstance {
return sharedInstance;
}