单例Singleton
先提供一个完整版:
// .h文件 @interface SingleTon : NSObject /** 获取单例对象 */ + (instancetype)sharedInstance; + (instancetype)new __attribute__((unavailable("new unavailable, call sharedInstance instead"))); - (instancetype)init __attribute__((unavailable("init unavailable, call sharedInstance instead"))); + (instancetype)alloc __attribute__((unavailable("alloc unavailable, call sharedInstance instead"))); @end // .m文件 static SingleTon *_instance; @implementation SingleTon + (instancetype)sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[super alloc] initInstance]; }); return _instance; } - (instancetype)initInstance { return [super init]; } + (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); return _instance; } - (id)copyWithZone:(NSZone *)zone { return _instance; } @end
建议构造单例对象时,禁止调用系统的alloc、init等方法。以防止新加入的程序员在调用时出现问题;
下面来如何说说‘禁用’init等方法:
1、Clang特性(推荐,xcode不会联想该方法)
- (instancetype)init __attribute__((unavailable("init unavailable, call sharedInstance instead")));
2、使用apple提供的宏
- (instancetype)init NS_UNAVAILABLE;
3、在.m的 init中实现:
- (instancetype)init { [super doesNotRecognizeSelector:_cmd]; return nil; }
若init方法被调用了,则抛出异常信息:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TestManager init]: unrecognized selector sent to instance 0x600000001150'
4、断言或使用NSException,在init被调用时,则抛出异常信息
// NSAssert断言 - (instancetype)init { NSAssert(false,@"init unavailable, use sharedInstance instead"); return nil; } // NSException - (instancetype)init { [NSException raise:NSGenericException format:@"init unavailable. use +[%@ %@] instead", NSStringFromClass([self class]), NSStringFromSelector(@selector(sharedInstance))]; return nil; }
参考:http://stackoverflow.com/questions/5720029/create-singleton-using-gcds-dispatch-once-in-objective-c