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

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

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

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

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

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

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

我们需要重写一些方法:

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

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

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

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

  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. return instance;
  11. }
  12. @end

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

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

该书推荐用

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

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

本类的allocWithZone被改写为:

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

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

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

【iOS】Objective-C简约而不简单的单例模式的更多相关文章

  1. IOS:利用dispatch_once创建单例

    在之前有一篇学习笔记中,记载了一篇如何在OC中实现单例的文章:<IOS学习笔记4—Objective C—创建单例>自苹果引入了Grand Central Dispatch (GCD)(M ...

  2. iOS开发笔记-两种单例模式的写法

    iOS开发笔记-两种单例模式的写法   单例模式是开发中最常用的写法之一,iOS的单例模式有两种官方写法,如下: 不使用GCD #import "ServiceManager.h" ...

  3. 通通玩blend美工(7)——简约而不简单的块

    原文:通通玩blend美工(7)--简约而不简单的块 最近在研发一个WPF快速开发框架,满脑子都是各种逻辑各种模式,写一篇比较休闲娱乐的博客,宣泄下我对美工的热爱. 我一直以来有意无意在手机应用或者各 ...

  4. 从Objective-C到Swift 单例模式

    在Objective-C中经常会用到单例模式.最常见的就是: [UIApplication sharedApplication].delegate 这里的sharedApplication就是一个返回 ...

  5. 【iOS开发】创建单例的两种方法

    创建一个单例很多办法.我先列举一个苹果官方文档中的写法. [cpp] view plaincopy   static AccountManager *DefaultManager = nil; + ( ...

  6. iOS开发——Swift篇&单例的实现

    Swift实现单例模式 Swift实现单例模式 由于Swift语言弱化了struct和class之间的界限,这里我分别给出自己写的两种的单例实现 class版本: class SwiftSinglet ...

  7. IOS GCD 使用(三)单例模式

    一  Dispatch_once函数简介      使用dispatch_once提价的代码块,即便你提交多次,只能执行一次.    void dispatch_once(dispatch_once_ ...

  8. iOS 开发中的单例

    在iOS开发中经常会用到单例,比如每个iOS程序本身就是一个单例,在比如进行个人偏好设置存储的时候用的也是一个单例.那我们如何自己来写一个单例类呢,用自己的单例对象呢?下面是我写的一个单例的头文件里的 ...

  9. Objective C—创建单例

    单例模式是在实际项目开发中用到比较多的一种设计模式,设计原理是整个系统只产生一个对象实例,通过一个统一的方法对外提供这个实例给外部使用. 在Java中,构造单例一般将类的构造函数声明为private类 ...

随机推荐

  1. js实现hashtable的赋值、取值、遍历

    哈希表(Hashtable)这个概率应该是#c里面的概念,用来赋值.取值.遍历.排序操作提高效率.想起这个东西其实使我们以前经常遇到这样的面试题,一个很大的数组可能有100000个,如何快速知道它里面 ...

  2. C#之使用随机数

    1.C#自带随机数函数 using System; System.Random ran = new System.Random();int n = ran.Next(100, 1000);//产生10 ...

  3. NAT

      WRITE BY YANGWJ 一.            配置静态Nat 实验图如下: 1.         将网络基本条件配置好,包括路由要可达,即pc1可以ping到server1 2.   ...

  4. php折线图 布局图

    例子1: 1 <?php require_once("../conf.php"); ?> <!DOCTYPE HTML> <html> < ...

  5. PowerDesigner提示This data item is already used in a primary identifier.的处理

    原文链接: http://blog.csdn.net/lopper/article/details/5293545 今天同事在编制一个数据库脚本的时候,提示了This data item is alr ...

  6. CodeForces 628D Magic Numbers (数位dp)

    题意:找到[a, b]符合下列要求的数的个数. 1.该数字能被m整除 2.该数字奇数位全不为d,偶数位全为d 分析: 1.dp[当前的位数][截止到当前位所形成的数对m取余的结果][当前数位上的数字是 ...

  7. DataGrid实现逻辑分页

    在ASP.NET内建提供的所有数据排列控件中,只有DataGrid数据控件是提供数据分页功能的.DataReapter数据控件只能提供一些简单 的.基础的数据重复排列功能,对于一些比较复杂的应用是无能 ...

  8. 查看某个模块的Tables

    在SE11 中 关于table的F4 help 有一个筛选条件是Package 同时由于不同的模块放在不同的Package中 很容易根据这个条件 获得某个模块的所有Tables     亲测有效  1 ...

  9. 4_1 wp8数据绑定与独立存储空间[wp8特色开发与编程技巧]

    Wp8数据绑定与独立存储空间 数据绑定为基于 Silverlight 的应用程序提供了一种显示数据并与数据进行交互的简便方法. 数据的显示方式独立于数据的管理. UI 和数据对象之间的连接或绑定使数据 ...

  10. 《shell脚本if..then..elif..then.if语句的总结》

    第一种: #!/bin/bash service vsftpd start &> /dev/null if [ $? -eq 0 ] then echo "ftp is sta ...