博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【iOS】Objective-C简约而不简单的单例模式
阅读量:7223 次
发布时间:2019-06-29

本文共 1961 字,大约阅读时间需要 6 分钟。

前些日子在项目中因为误用了单例而导致了一系列问题。原来在objective-c中的单例并没有java或者C#那么简单的实现,这里记录下;

 

问题是这样被发现的,在对于一个UIViewController进行pop时并没有被dealloc,导致了内存泄露。问题代码类似于下面的:

 

C代码
  
  1. //LWChatViewController.h  
  2. @interface LWChatViewController : LWTableViewController <LWObjSelectViewDelegate>{  
  3.     UINavigationController *root;  
  4. }  
  5. @property (nonatomic, retain) UINavigationController *root;  
  6. @end  
  7.   
  8. //LWChatViewController.m  
  9. - (void)viewDidLoad  
  10. {  
  11.     [super viewDidLoad];  
  12.     // Do any additional setup after loading the view from its nib.  
  13.     self.root = LWNavigationController;  
  14. }  

 

  这里的LWNavigationController是一个顶级的单例。

问题就出在@property (nonatomic, retain) 这里root居然是一个retain的对象指针,在这里retain一个static的单例将导致内存泄露,MD,这个bug找的我好久。。。

 

 

解决这个问题其实很简单,把retain改为assign就行了,但这样如果在协作编程的时候如果别人不在意这个是单例直接进行常规操作的话会带来很大的问题。

 

 

继续,我们来从根本上解决这个问题。

我们需要重写一些方法:

 

C代码
  
  1. - (id)retain  
  2. {  
  3.     return self;  
  4. }  
  5.   
  6. - (NSUInteger) retainCount  
  7. {  
  8.     return NSUIntegerMax;  
  9. }  
  10.   
  11. - (void) release  
  12. {  
  13.     // do nothing  
  14. }  
  15.   
  16. - (id)autorelease  
  17. {  
  18.     return self;  
  19. }  

在retain和autorelease什么都不做只是返回自己,release的时候啥都不做,将retainCount设为UInt的极大值。

 

其次是关于线程安全的实现,这些java都有明确的代码模式:

关于线程安全的单例,这篇外文 http://www.numbergrinder.com/2008/12/patterns-in-objective-c-singleton-pattern/ 有比较详细的解释。

 

 

Java代码
  
  1. @implementation Singleton  
  2. static Singleton *instance = nil;  
  3. + (Singleton *)sharedInstance  {  
  4.    @synchronized(self)   
  5.    {  
  6.         if(!instance) {  
  7.            instance = [[Singleton alloc] init];  
  8.         }  
  9.     }  
  10.    
  11.     return instance;  
  12. }  
  13.    
  14. @end  

 

嗯,这样就可以实现线程安全的单例了,当然这里也可以用NSLock实例去实现。

 

最后趁机深入了下单例模式,发现instance = [[Singleton alloc] init];这样的语句是有问题的,它不能以其他方式发起分配内存去实例化对象,可能会造成多个实例被创建。(见《pro objective-c design patterns for ios》 )

该书推荐用

 

C代码
  
  1. instance = [[super allocWithZone:NULL] init];  

 

传NULL到allocWithZone其实等同与alloc默认方法,但注意这里是调用super的alloc;

 

本类的allocWithZone被改写为:

 

C代码
  
  1. + (id)allocWithZone:(NSZone *)zone  
  2. {  
  3.       return [self sharedInstance];  
  4. }  
  5.   
  6. - (id)copyWithZone:(NSZone *)zone  
  7. {  
  8.       return self;  
  9. }  

 同时深拷贝也直接重载阻止掉多个实例的出现。上面的allocWithZone的重载使得这个单例也能够直接用alloc或是allocWithZone进行初始化,但返回的一如既往是那个static的实例。

 

这样一个objective-c的单例模式才算是完整了。。。啦啦啦,每月末一博写完,睡觉去了。。。

转载于:https://www.cnblogs.com/lovewx/p/3955559.html

你可能感兴趣的文章
[Algorithms] Solve Complex Problems in JavaScript with Dynamic Programming
查看>>
MetaModelEngine:约束和验证
查看>>
垂直居中层 js操作css
查看>>
c_str 以及atoi
查看>>
Wrox红皮书上市十周年 惊喜馈赠读者
查看>>
ASP.NET运行时错误
查看>>
acdream 1014 Dice Dice Dice(组合)
查看>>
(DT系列六)devicetree中数据和 struct device有什么关系
查看>>
javascript异步编程系列【七】----扫盲,我们为什么要用Jscex
查看>>
.N“.NET研究”ET中的异步编程(二)- 传统的异步编程
查看>>
C#汉字转拼音代码分享|建议收藏
查看>>
WindowsServer2003+IIS6+ASP+NET+PHP+MSSQL+MYSQL配置说明 |备份于waw.cnblogs.com
查看>>
opengl 链接
查看>>
MVC 数据验证
查看>>
MVC中几种常用ActionResult
查看>>
.NET中使用OracleHelper
查看>>
[BuildRelease]安装文件的种类
查看>>
周鸿祎向雷军开炮:山寨成不了乔布斯
查看>>
WYSE POCKETCLOUD手把手教你如何用手机遥控你的电脑!!(转)
查看>>
[转载]最锋利的Visual Studio Web开发工具扩展:Web Essentials详解
查看>>