今天在修改数据库,发现每个类都有自己的单例实现函数,然后很多冗余的逻辑,于是就想父类写一个单例函数,然后子类继承就可以生成各自的单例了.
结果发现俺错了...
+ (id)sharedInstance{
static BaseDAO *kInstance = nil;
NSLog(@"kInstance=%@", kInstance);
@synchronized(self){
if(kInstance == nil){
kInstance = [[self alloc] init];
}else{
}
}
return kInstance;
}
结果是所有的子类得到的都是同一个单例,然后就unrecognized selector sent to instance
我看了下java是有这种功能的,因为可以把属性设置为static, oc刚试了不行.
不知道有木有方法实现各子类不同单例.
先说你错在哪:
虽然方法中self
是不同的类,但是kInstance
只有一个。
你只用[BaseDAO sharedInstance];
一直都不会出问题
一旦[XXX sharedInstance];
kInstance
已存在,不会再重新生成,返回的就是BaseDAO
的单例。你对着BaseDAO
的对象发XXX
的消息当然会unrec sel。
总之,kInstace
存的一直都是第一次调用sharedInstance
时,接收消息的类的单例
你耳朵里有没有偶尔回旋起这样一句话:
多用组合,少用继承
你如果觉得用组合有绕路的感觉,我来炫下技:
NSObject+OTSharedInstance.h:
@interface NSObject (OTSharedInstance) + (id)sharedInstance; @end
NSObject+OTSharedInstance.m:
#import <objc/runtime.h> @implementation NSObject (OTSharedInstance) + (id)sharedInstance { Class selfClass = [self class]; id instance = objc_getAssociatedObject(selfClass, @"kOTSharedInstance"); if (!instance) { instance = [[selfClass alloc] init]; objc_setAssociatedObject(selfClass, @"kOTSharedInstance", instance, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return instance; } @end
内存不够用的话可能需要释放单例,补个释放的方法:
+ (void)freeSharedInstance { Class selfClass = [self class]; objc_setAssociatedObject(selfClass, SHARED_INSTANCE_KEY, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }
测试代码:
#import "NSObject+OTSharedInstance.h" id a; id b; for (int i = 0; i<10; i++) { a = [UIWindow sharedInstance]; NSLog(@"instance a : %@",a); b = [UIView sharedInstance]; NSLog(@"instance b : %@",b); }
如果你觉得用了上述方法,所有类都能产生单例太脏,可以新建个Protocol
,单在Protocol
中声明sharedInstace
。需要单例的类自己多重继承一下
好用的话把答案勾给我
歪一下。现在我的单例这么写
+ (class *)accessor { static dispatch_once_t once; static class *singleton; dispatch_once(&once, ^ { singleton = [[class alloc] init]; }); return singleton; }