00
原來在項目中寫過一個生成單例的宏才漆, 可以很方便的定義單例:
//
// Singleton_Template.h
// patchwork
//
// Created by Alex Lee on 3/11/15.
// Copyright ? 2015 Alex Lee. All rights reserved.
//
#undef AS_SINGLETON
#define AS_SINGLETON \
+ (instancetype)sharedInstance; \
+ (void)destroy;
#if __has_feature(objc_arc)
# undef SYNTHESIZE_SINGLETON
# define SYNTHESIZE_SINGLETON \
static id __singleton_instance__ = nil; \
+ (instancetype)sharedInstance { \
@synchronized(self) { \
if (__singleton_instance__) { \
return __singleton_instance__; \
} \
} \
return [[self alloc] init]; \
} \
\
+ (instancetype)allocWithZone:(struct _NSZone *)zone { \
static dispatch_once_t onceToken; \
dispatch_once( &onceToken, ^{ __singleton_instance__ = [super allocWithZone:zone]; } ); \
return __singleton_instance__; \
} \
\
+ (instancetype)alloc { \
return [self allocWithZone:NULL]; \
} \
\
+ (instancetype)new { \
return [self allocWithZone:NULL]; \
} \
\
- (id)copy { return self; } \
- (id)mutableCopy { return self; } \
\
+ (void)destroy { \
__singleton_instance__ = nil; \
}
#else
# undef SYNTHESIZE_SINGLETON
# define SYNTHESIZE_SINGLETON \
static id __singleton_instance__ = nil; \
+ (instancetype)sharedInstance { \
return [[self alloc] init]; \
} \
\
+ (instancetype)allocWithZone:(struct _NSZone *)zone { \
static dispatch_once_t onceToken; \
dispatch_once( &onceToken, ^{ __singleton_instance__ = [super allocWithZone:zone]; } ); \
return __singleton_instance__; \
} \
\
+ (instancetype)alloc { \
return [self allocWithZone:NULL]; \
} \
\
+ (instancetype)new { \
return [self allocWithZone:NULL]; \
} \
\
- (id)copy { return self; } \
- (id)mutableCopy { return self; } \
\
+ (id)copyWithZone:(struct _NSZone *) { return self; } \
+ (id)mutableCopyWithZone:(struct _NSZone *) { return self; } \
\
- (instancetype)retain { return self; } \
- (oneway void)release {} \
- (instancetype)autorelease { return self; }\
- (NSUInteger)retainCount { return NSUIntegerMax; } \
\
+ (void)destroy { \
[__singleton_instance__ dealloc]; \
__singleton_instance__ = nil; \
} \
#endif
使用方式也很簡單:
#pragma mark - singleton test
@interface SingletonTestBase : NSObject
AS_SINGLETON
// other properties
// other methods
@end
@implementation SingletonTestBase
SYNTHESIZE_SINGLETON
- (NSString *)whoAmI {
return @"SingletonTestBase";
}
// other code here ...
@end
外界無論用何種初始化方式, 都只能得到一個實例:
SingletonTestBase *base = [SingletonTestBase sharedInstance];
XCTAssertEqualObjects(base, [[SingletonTestBase alloc] init]); // ?
XCTAssertEqualObjects(base, [base copy]); // ?
XCTAssertEqualObjects(base, [SingletonTestBase new]); // ?
01
今天突然想到個問題柒昏, 貌似以后有沒有可能需要能繼承某個單例的情況呢显蝌? 于是測試了一下:
#pragma mark - singleton test
@interface SingletonTestBase : NSObject
AS_SINGLETON
@end
@implementation SingletonTestBase
SYNTHESIZE_SINGLETON
- (NSString *)whoAmI {
return @"SingletonTestBase";
}
@end
@interface SingletonSubClass : SingletonTestBase
@end
@implementation SingletonSubClass
- (NSString *)whoAmI {
return @"SingletonSubClass";
}
@end
- (void)testSingleton {
SingletonTestBase *base = [SingletonTestBase sharedInstance];
XCTAssertEqualObjects(@"SingletonTestBase", [base whoAmI]); // ?
SingletonSubClass *child = [SingletonSubClass sharedInstance];
XCTAssertEqualObjects(@"SingletonSubClass", [child whoAmI]); // ?
XCTAssertEqualObjects(@"SingletonTestBase", [child whoAmI]); // ?
XCTAssertEqualObjects(base, child); // ?
}
你沒看錯, base == child
, 就是說破喻, 某個類加了SYNTHESIZE_SINGLETON
虎谢, 它就成了太監(jiān)了, 所有的『子類』其實都是他自己而已曹质。
這可怎么辦呢婴噩??羽德? :(
02
一切都是那該死的『static id singleton_instance = nil;』
挽起袖子自個擼~~
//
// Singleton_Template.h
// patchwork
//
// Created by Alex Lee on 3/11/15.
// Copyright ? 2015 Alex Lee. All rights reserved.
//
#undef AS_SINGLETON
#define AS_SINGLETON \
+ (instancetype)sharedInstance; \
#undef __AL_SYNTHESIZE_SINGLETON
#define __AL_SYNTHESIZE_SINGLETON \
static NSMutableDictionary *__al_singleton_instance_dict__ = nil; \
static NSMutableDictionary *__al_singleton_zone_dict__ = nil; \
+ (instancetype)sharedInstance { \
static dispatch_semaphore_t localSem; \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
localSem = dispatch_semaphore_create(1); \
}); \
\
dispatch_semaphore_wait(localSem, DISPATCH_TIME_FOREVER); \
NSString *_al_key_ = NSStringFromClass(self); \
id __instance__ = __al_singleton_instance_dict__[_al_key_]; \
if (__instance__ == nil) { \
__instance__ = [[self alloc] init]; \
if (__instance__) { \
__al_singleton_instance_dict__[_al_key_] = __instance__; \
} \
} \
dispatch_semaphore_signal(localSem); \
return __instance__; \
} \
\
+ (instancetype)allocWithZone:(struct _NSZone *)zone { \
static dispatch_semaphore_t localSem; \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
localSem = dispatch_semaphore_create(1); \
__al_singleton_instance_dict__ = [NSMutableDictionary dictionary]; \
__al_singleton_zone_dict__ = [NSMutableDictionary dictionary]; \
}); \
\
dispatch_semaphore_wait(localSem, DISPATCH_TIME_FOREVER); \
NSString *_al_key_ = NSStringFromClass(self); \
id __zone__ = __al_singleton_zone_dict__[_al_key_]; \
if (__zone__ == nil) { \
__zone__ = [super allocWithZone:zone]; \
if (__zone__) { \
__al_singleton_zone_dict__[_al_key_] = __zone__; \
} \
} \
dispatch_semaphore_signal(localSem); \
return __zone__; \
} \
\
+ (instancetype)alloc { \
return [self allocWithZone:NULL]; \
} \
\
+ (instancetype)new { \
return [[self alloc] init]; \
} \
\
- (id)copyWithZone:(nullable NSZone *)zone { \
return self; \
} \
- (id)mutableCopyWithZone:(nullable NSZone *)zone { \
return self; \
} \
- (id)copy { return self; } \
- (id)mutableCopy { return self; } \
#undef SYNTHESIZE_SINGLETON
#if __has_feature(objc_arc)
#define SYNTHESIZE_SINGLETON __AL_SYNTHESIZE_SINGLETON
#else
#define SYNTHESIZE_SINGLETON \
__AL_SYNTHESIZE_SINGLETON \
\
- (instancetype)retain { return self; } \
- (oneway void)release {} \
- (instancetype)autorelease { return self; } \
- (NSUInteger)retainCount { return NSUIntegerMax; } \
#endif
再測試~
#pragma mark - singleton test
@interface SingletonTestBase : NSObject
AS_SINGLETON
@end
@implementation SingletonTestBase
SYNTHESIZE_SINGLETON
- (NSString *)whoAmI {
return @"SingletonTestBase";
}
@end
@interface SingletonSubClass : SingletonTestBase
@end
@implementation SingletonSubClass
- (NSString *)whoAmI {
return @"SingletonSubClass";
}
@end
@interface SingletonChildSubClass : SingletonSubClass
@end
@implementation SingletonChildSubClass
- (NSString *)whoAmI {
return @"SingletonChildSubClass";
}
@end
@interface SingletonSubClass1 : SingletonTestBase
@end
@implementation SingletonSubClass1
- (NSString *)whoAmI {
return @"SingletonSubClass1";
}
@end
- (void)testSingleton {
SingletonTestBase *base = [SingletonTestBase sharedInstance];
XCTAssertEqualObjects(base, [[SingletonTestBase alloc] init]);
XCTAssertEqualObjects(base, [base copy]);
XCTAssertEqualObjects(base, [SingletonTestBase new]);
XCTAssertEqualObjects(base, [base copyWithZone:NULL]);
ALLogInfo(@"%@", [base whoAmI]);
XCTAssertEqualObjects(@"SingletonTestBase", [base whoAmI]);
base = nil;
XCTAssertNotNil([SingletonTestBase sharedInstance]);
SingletonSubClass *child = [SingletonSubClass sharedInstance];
ALLogInfo(@"%@", [child whoAmI]);
XCTAssertEqualObjects(@"SingletonSubClass", [child whoAmI]);
XCTAssertEqualObjects(child, [[SingletonSubClass alloc] init]);
XCTAssertEqualObjects(child, [child copy]);
//XCTAssertEqualObjects(child, [SingletonTestBase sharedInstance]); ?
XCTAssertNotEqualObjects(child, [SingletonTestBase sharedInstance]);
XCTAssertNotEqualObjects([SingletonChildSubClass sharedInstance], [SingletonTestBase sharedInstance]);
XCTAssertNotEqualObjects([SingletonChildSubClass sharedInstance], [SingletonSubClass sharedInstance]);
XCTAssertNotEqualObjects([SingletonChildSubClass sharedInstance], [SingletonSubClass1 sharedInstance]);
XCTAssertNotEqualObjects([SingletonSubClass sharedInstance], [SingletonSubClass1 sharedInstance]);
}
恩几莽, 終于不是太監(jiān)了, 也就是說宅静, 只要某個類定義加上了SYNTHESIZE_SINGLETON
, 保證就是千秋萬代都是獨生子了章蚣。
問題來了:
什么情況需要繼承一個單例呢?姨夹?究驴?
~~沒有困難, 創(chuàng)造困難也要做粗來~~