【iOS】Objective-C简约而不简单的单例模式
2012-09-29 15:16
190 查看
前些日子在项目中因为误用了单例而导致了一系列问题。原来在objective-c中的单例并没有java或者C#那么简单的实现,这里记录下;
问题是这样被发现的,在对于一个UIViewController进行pop时并没有被dealloc,导致了内存泄露。问题代码类似于下面的:
C代码
//LWChatViewController.h
@interface LWChatViewController : LWTableViewController <LWObjSelectViewDelegate>{
UINavigationController *root;
}
@property (nonatomic, retain) UINavigationController *root;
@end
//LWChatViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.root = LWNavigationController;
}
这里的LWNavigationController是一个顶级的单例。
问题就出在@property (nonatomic, retain) 这里root居然是一个retain的对象指针,在这里retain一个static的单例将导致内存泄露,MD,这个bug找的我好久。。。
解决这个问题其实很简单,把retain改为assign就行了,但这样如果在协作编程的时候如果别人不在意这个是单例直接进行常规操作的话会带来很大的问题。
继续,我们来从根本上解决这个问题。
我们需要重写一些方法:
C代码
- (id)retain
{
return self;
}
- (NSUInteger) retainCount
{
return NSUIntegerMax;
}
- (void) release
{
// do nothing
}
- (id)autorelease
{
return self;
}
在retain和autorelease什么都不做只是返回自己,release的时候啥都不做,将retainCount设为UInt的极大值。
其次是关于线程安全的实现,这些java都有明确的代码模式:
关于线程安全的单例,这篇外文 http://www.numbergrinder.com/2008/12/patterns-in-objective-c-singleton-pattern/ 有比较详细的解释。
Java代码
@implementation Singleton
static Singleton *instance = nil;
+ (Singleton *)sharedInstance {
@synchronized(self)
{
if(!instance) {
instance = [[Singleton alloc] init];
}
}
return instance;
}
@end
嗯,这样就可以实现线程安全的单例了,当然这里也可以用NSLock实例去实现。
最后趁机深入了下单例模式,发现instance = [[Singleton alloc] init];这样的语句是有问题的,它不能以其他方式发起分配内存去实例化对象,可能会造成多个实例被创建。(见《pro objective-c design patterns for ios》 )
该书推荐用
C代码
instance = [[super allocWithZone:NULL] init];
传NULL到allocWithZone其实等同与alloc默认方法,但注意这里是调用super的alloc;
本类的allocWithZone被改写为:
C代码
+ (id)allocWithZone:(NSZone *)zone
{
return [self sharedInstance];
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
同时深拷贝也直接重载阻止掉多个实例的出现。上面的allocWithZone的重载使得这个单例也能够直接用alloc或是allocWithZone进行初始化,但返回的一如既往是那个static的实例。
这样一个objective-c的单例模式才算是完整了。。。啦啦啦,每月末一博写完,睡觉去了。。。
问题是这样被发现的,在对于一个UIViewController进行pop时并没有被dealloc,导致了内存泄露。问题代码类似于下面的:
C代码
//LWChatViewController.h
@interface LWChatViewController : LWTableViewController <LWObjSelectViewDelegate>{
UINavigationController *root;
}
@property (nonatomic, retain) UINavigationController *root;
@end
//LWChatViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.root = LWNavigationController;
}
这里的LWNavigationController是一个顶级的单例。
问题就出在@property (nonatomic, retain) 这里root居然是一个retain的对象指针,在这里retain一个static的单例将导致内存泄露,MD,这个bug找的我好久。。。
解决这个问题其实很简单,把retain改为assign就行了,但这样如果在协作编程的时候如果别人不在意这个是单例直接进行常规操作的话会带来很大的问题。
继续,我们来从根本上解决这个问题。
我们需要重写一些方法:
C代码
- (id)retain
{
return self;
}
- (NSUInteger) retainCount
{
return NSUIntegerMax;
}
- (void) release
{
// do nothing
}
- (id)autorelease
{
return self;
}
在retain和autorelease什么都不做只是返回自己,release的时候啥都不做,将retainCount设为UInt的极大值。
其次是关于线程安全的实现,这些java都有明确的代码模式:
关于线程安全的单例,这篇外文 http://www.numbergrinder.com/2008/12/patterns-in-objective-c-singleton-pattern/ 有比较详细的解释。
Java代码
@implementation Singleton
static Singleton *instance = nil;
+ (Singleton *)sharedInstance {
@synchronized(self)
{
if(!instance) {
instance = [[Singleton alloc] init];
}
}
return instance;
}
@end
嗯,这样就可以实现线程安全的单例了,当然这里也可以用NSLock实例去实现。
最后趁机深入了下单例模式,发现instance = [[Singleton alloc] init];这样的语句是有问题的,它不能以其他方式发起分配内存去实例化对象,可能会造成多个实例被创建。(见《pro objective-c design patterns for ios》 )
该书推荐用
C代码
instance = [[super allocWithZone:NULL] init];
传NULL到allocWithZone其实等同与alloc默认方法,但注意这里是调用super的alloc;
本类的allocWithZone被改写为:
C代码
+ (id)allocWithZone:(NSZone *)zone
{
return [self sharedInstance];
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
同时深拷贝也直接重载阻止掉多个实例的出现。上面的allocWithZone的重载使得这个单例也能够直接用alloc或是allocWithZone进行初始化,但返回的一如既往是那个static的实例。
这样一个objective-c的单例模式才算是完整了。。。啦啦啦,每月末一博写完,睡觉去了。。。
相关文章推荐
- 【iOS】Objective-C简约而不简单的单例模式
- 【iOS】Objective-C简约而不简单的单例模式
- Objective-C简约而不简单的单例模式
- Objective-C编程之道iOS设计模式单例解析(2)
- iOS疯狂讲解之单例模式传值的简单介绍
- iOS监听模式系列之NSNotificationCenter的简单使用
- iOS设计模式:简单工厂模式
- iOS策略模式的简单应用
- iOS设计模式之KVO Key-Value Observing 键值观察者模式的简单实用和介绍
- 设计模式之装饰模式(iOS开发,代码用Objective-C展示)
- iOS监听模式系列之NSNotificationCenter的简单使用
- [置顶] Objective-C编程之道iOS设计模式单例解析(2)
- iOS学习(二十八)Objective-C 代理设计模式
- [iOS] Objective-C的单件模式
- iOS设计模式――Category简单介绍
- ios开发中的基本设计模式 (简单归类)
- IOS之Objective-C学习 代理设计模式
- Objective-C编程之道iOS设计模式子类化单例疑惑
- iOS开发-简单工厂模式
- IOS之Objective-C学习 ARC下的单例模式