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
, 它就成了太监了, 所有的『子类』其实都是他自己而已。
这可怎么办呢??? :(
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]);
}
恩, 终于不是太监了, 也就是说, 只要某个类定义加上了SYNTHESIZE_SINGLETON
, 保证就是千秋万代都是独生子了。
问题来了:
什么情况需要继承一个单例呢???
~~没有困难, 创造困难也要做粗来~~