Mac / iOS中的單例繼承

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)造困難也要做粗來~~

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末匀伏,一起剝皮案震驚了整個濱河市洒忧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌够颠,老刑警劉巖熙侍,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異履磨,居然都是意外死亡蛉抓,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門剃诅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來巷送,“玉大人,你說我怎么就攤上這事矛辕⌒︴耍” “怎么了付魔?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長飞蹂。 經(jīng)常有香客問我几苍,道長,這世上最難降的妖魔是什么陈哑? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任妻坝,我火速辦了婚禮,結果婚禮上惊窖,老公的妹妹穿的比我還像新娘刽宪。我一直安慰自己,他們只是感情好界酒,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布纠屋。 她就那樣靜靜地躺著,像睡著了一般盾计。 火紅的嫁衣襯著肌膚如雪售担。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天署辉,我揣著相機與錄音族铆,去河邊找鬼。 笑死哭尝,一個胖子當著我的面吹牛哥攘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播材鹦,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼逝淹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了桶唐?” 一聲冷哼從身側響起栅葡,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎尤泽,沒想到半個月后欣簇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡坯约,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年熊咽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闹丐。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡横殴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卿拴,到底是詐尸還是另有隱情衫仑,我是刑警寧澤梨与,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站惑畴,受9級特大地震影響蛋欣,放射性物質(zhì)發(fā)生泄漏航徙。R本人自食惡果不足惜如贷,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望到踏。 院中可真熱鬧杠袱,春花似錦、人聲如沸窝稿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伴榔。三九已至纹蝴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間踪少,已是汗流浹背塘安。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留援奢,地道東北人兼犯。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像集漾,于是被迫代替她去往敵國和親切黔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容