zoukankan      html  css  js  c++  java
  • 【iOS】Objective-C简约而不简单的单例模式

    前些日子在项目中因为误用了单例而导致了一系列问题。原来在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的单例模式才算是完整了。。。啦啦啦,每月末一博写完,睡觉去了。。。

  • 相关阅读:
    关于Maya Viewport 2.0 API 开发的介绍视频
    春节大假
    Some tips about the life cycle of Maya thread pool
    Can I compile and run Dx11Shader for Maya 2015 on my side?
    How to get current deformed vertex positions in MoBu?
    想加入全球首届的 欧特克云加速计划吗?
    三本毕业(非科班),四次阿里巴巴面试,终拿 offer(大厂面经)
    mac、window版编辑器 webstorm 2016... 永久破解方法。
    node 搭载本地代理,处理web本地开发跨域问题
    js 一维数组,转成嵌套数组
  • 原文地址:https://www.cnblogs.com/lovewx/p/3955559.html
Copyright © 2011-2022 走看看