一句话实现单例模式

如题

效果如下:

@interface AAA : NSObject <MySingleton>

@end

单例模式是开发中经常会涉及到的开发结构,实现单例模式的代码大多千篇一律。

网上也有很多大神,简化了单例的实现。大多数是用宏定义将需要写的代码进行了封装,需要在.h文件中处理,也需要在.m文件中再处理。懒人简直不能忍!!

sunnyxx大神提到了一个通过__attribute__((objc_runtime_name("othername")))封装的@singleton(Class, instanceMethod)的方法,受此启发,做了一个尝试:

首先,定义一个<单例协议>

@protocol MySingleton

@optional

+ (instancetype)sharedInstance;

@end

对于需要实现单例的类,则扩展此单例协议

然后,思路就是,在系统加载之前,通过runtime方法,对扩展了此协议的类的allocWithZone:和copyWithZone:等方法进行添加替换:

@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

此方法优点就是:几乎没有什么优点,就是写法简单。

缺点:

1、需要在app启动时做一些处理,对效率有或多或少的影响(取决于具体的替换方法实现)

2、对实现了单例协议的Class的特定method进行了强制替换,导致需要实现的单例类对这几个method的实现无效,如果需要在alloc或者copy中做处理,则不能应用此法;当然,也可以在替换时做检测,如果存在此method则不替换,但是这就不能保证完全单例。(值得一提的是,检测是否存在此方法时,不能用class_getInstanceMethod,此方法会查找父类)

你可能感兴趣的:(一句话实现单例模式)