一句話實(shí)現(xiàn)單例模式

如題

效果如下:

@interface AAA : NSObject <MySingleton>

@end

單例模式是開(kāi)發(fā)中經(jīng)常會(huì)涉及到的開(kāi)發(fā)結(jié)構(gòu),實(shí)現(xiàn)單例模式的代碼大多千篇一律。

網(wǎng)上也有很多大神,簡(jiǎn)化了單例的實(shí)現(xiàn)。大多數(shù)是用宏定義將需要寫的代碼進(jìn)行了封裝,需要在.h文件中處理,也需要在.m文件中再處理。懶人簡(jiǎn)直不能忍????!

sunnyxx大神提到了一個(gè)通過(guò)__attribute__((objc_runtime_name("othername")))封裝的@singleton(Class, instanceMethod)的方法,受此啟發(fā),做了一個(gè)嘗試:

首先,定義一個(gè)<單例協(xié)議>

@protocol MySingleton <NSObject>

@optional

+ (instancetype)sharedInstance;

@end

對(duì)于需要實(shí)現(xiàn)單例的類,則擴(kuò)展此單例協(xié)議

然后,思路就是,在系統(tǒng)加載之前,通過(guò)runtime方法,對(duì)擴(kuò)展了此協(xié)議的類的allocWithZone:和copyWithZone:等方法進(jìn)行添加替換:

@interface SingleObj : NSObject

@end

@implementation SingleObj

+ (void)load {

? ? int numClasses;

? ? Class*classes;

? ? classes =NULL;

? ? numClasses =objc_getClassList(NULL,0);

? ? if(numClasses >0) {

? ? ? ? classes = (Class*)malloc(sizeof(Class) * numClasses);

? ? ? ? numClasses =objc_getClassList(classes, numClasses);

? ? ? ? for(inti =0; i < numClasses; i++) {

? ? ? ? ? ? Class cls = classes[i];

? ? ? ? ? ? if (class_conformsToProtocol(cls, NSProtocolFromString(@"MySingleton"))) {

? ? ? ? ? ? ? ? //override allocWithZone:

? ? ? ? ? ? ? ? MethodclsMethod =class_getClassMethod(cls,@selector(allocWithZone:));

? ? ? ? ? ? ? ? id metaCls = objc_getMetaClass(NSStringFromClass(cls).UTF8String);

? ? ? ? ? ? ? ? if(clsMethod !=NULL) {

? ? ? ? ? ? ? ? ? ? Method method =class_getClassMethod(self,@selector(allocWithZone:));

? ? ? ? ? ? ? ? ? ? class_replaceMethod(metaCls,@selector(allocWithZone:),method_getImplementation(method),"@@:@");

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? //implementation sharedInstance

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? SEL SEL_sharedInstance =NSSelectorFromString(@"sharedInstance");

? ? ? ? ? ? ? ? ? ? Method Method_sharedInstance =class_getClassMethod(metaCls, SEL_sharedInstance);

? ? ? ? ? ? ? ? ? ? Method Method_sharedInstance_toApply =class_getClassMethod(self, SEL_sharedInstance);

? ? ? ? ? ? ? ? ? ? IMP IMP_sharedInstance =method_getImplementation(Method_sharedInstance_toApply);

? ? ? ? ? ? ? ? ? ? if(Method_sharedInstance ==NULL) {

? ? ? ? ? ? ? ? ? ? ? ? class_addMethod(metaCls, SEL_sharedInstance, IMP_sharedInstance,"@@:");

? ? ? ? ? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? ? ? ? ? class_replaceMethod(metaCls, SEL_sharedInstance, IMP_sharedInstance,"@@:");

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? //override copyWithZone:

? ? ? ? ? ? ? ? uintmethodCount =0;

? ? ? ? ? ? ? ? Method*methods =class_copyMethodList(cls, &methodCount);

? ? ? ? ? ? ? ? Method methodToApply =class_getClassMethod(self,@selector(copyWithZone:));

? ? ? ? ? ? ? ? IMP imp =method_getImplementation(methodToApply);

? ? ? ? ? ? ? ? BOOL copyWithZone =NO;

? ? ? ? ? ? ? ? for(inti =0; i < methodCount; i++) {

? ? ? ? ? ? ? ? ? ? Method method = methods[i];

? ? ? ? ? ? ? ? ? ? SEL sel =method_getName(method);

? ? ? ? ? ? ? ? ? ? if(sel ==@selector(copyWithZone:)) {

? ? ? ? ? ? ? ? ? ? ? ? class_replaceMethod(cls,@selector(copyWithZone:), imp,"@@:@");

? ? ? ? ? ? ? ? ? ? ? ? copyWithZone =YES;

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? if(!copyWithZone) {

? ? ? ? ? ? ? ? ? ? class_addMethod(cls,@selector(copyWithZone:), imp,"@@:@");

? ? ? ? ? ? ? ? }

#if __has_feature(objc_arc)

#else

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? SEL sel = NSSelectorFromString(@"retain");

? ? ? ? ? ? ? ? ? ? Method method = class_getInstanceMethod(metaCls, sel);

? ? ? ? ? ? ? ? ? ? Method methodToApply = class_getInstanceMethod(self,@selector(returnSelf));

? ? ? ? ? ? ? ? ? ? IMP imp = method_getImplementation(methodToApply);

? ? ? ? ? ? ? ? ? ? if(method ==NULL) {

? ? ? ? ? ? ? ? ? ? ? ? class_addMethod(cls, sel, imp,"@@:");

? ? ? ? ? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? ? ? ? ? class_replaceMethod(cls, sel, imp,"@@:");

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? SEL sel = NSSelectorFromString(@"autorelease");

? ? ? ? ? ? ? ? ? ? Method method = class_getInstanceMethod(metaCls, sel);

? ? ? ? ? ? ? ? ? ? Method methodToApply = class_getInstanceMethod(self,@selector(returnSelf));

? ? ? ? ? ? ? ? ? ? IMP imp = method_getImplementation(methodToApply);

? ? ? ? ? ? ? ? ? ? if(method ==NULL) {

? ? ? ? ? ? ? ? ? ? ? ? class_addMethod(cls, sel, imp,"@@:");

? ? ? ? ? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? ? ? ? ? class_replaceMethod(cls, sel, imp,"@@:");

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? SEL sel = NSSelectorFromString(@"release");

? ? ? ? ? ? ? ? ? ? Method method = class_getInstanceMethod(metaCls, sel);

? ? ? ? ? ? ? ? ? ? Method methodToApply = class_getInstanceMethod(self,@selector(doNothing));

? ? ? ? ? ? ? ? ? ? IMP imp = method_getImplementation(methodToApply);

? ? ? ? ? ? ? ? ? ? if(method ==NULL) {

? ? ? ? ? ? ? ? ? ? ? ? class_addMethod(cls, sel, imp,"v@:");

? ? ? ? ? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? ? ? ? ? class_replaceMethod(cls, sel, imp,"v@:");

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? SEL sel = NSSelectorFromString(@"retainCount");

? ? ? ? ? ? ? ? ? ? Method method = class_getInstanceMethod(metaCls, sel);

? ? ? ? ? ? ? ? ? ? Method methodToApply = class_getInstanceMethod(self,@selector(maxCount));

? ? ? ? ? ? ? ? ? ? IMP imp = method_getImplementation(methodToApply);

? ? ? ? ? ? ? ? ? ? if(method ==NULL) {

? ? ? ? ? ? ? ? ? ? ? ? class_addMethod(cls, sel, imp,"i@:");

? ? ? ? ? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? ? ? ? ? class_replaceMethod(cls, sel, imp,"i@:");

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

#endif

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? free(classes);

? ? }

}

+ (instancetype)sharedInstance {

? ? return self.new;

}

+ (instancetype)allocWithZone:(NSZone*)zone {

? ? static id instance =nil;

? ? @synchronized (self) {

? ? ? ? if(!instance) {

? ? ? ? ? ? instance = [superallocWithZone:zone];

? ? ? ? }

? ? }

? ? returninstance;

}

- (instancetype)copyWithZone:(NSZone*)zone {

? ? return self;

}

#if __has_feature(objc_arc)

#else

- (void)doNothing {

}

- (instancetype)returnSelf {

? ? return self;

}

- (int)maxCount {

? ? returnINT_MAX;

}

#endif

@end

此方法優(yōu)點(diǎn)就是:幾乎沒(méi)有什么優(yōu)點(diǎn)??,就是寫法簡(jiǎn)單。

缺點(diǎn):

1、需要在app啟動(dòng)時(shí)做一些處理,對(duì)效率有或多或少的影響(取決于具體的替換方法實(shí)現(xiàn))

2、對(duì)實(shí)現(xiàn)了單例協(xié)議的Class的特定method進(jìn)行了強(qiáng)制替換,導(dǎo)致需要實(shí)現(xiàn)的單例類對(duì)這幾個(gè)method的實(shí)現(xiàn)無(wú)效,如果需要在alloc或者copy中做處理,則不能應(yīng)用此法;當(dāng)然,也可以在替換時(shí)做檢測(cè),如果存在此method則不替換,但是這就不能保證完全單例。(值得一提的是,檢測(cè)是否存在此方法時(shí),不能用class_getInstanceMethod,此方法會(huì)查找父類)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容