单例模式保证一个类只能拥有一个静态的实例,类负责创建与维护这个实例,并提供一个统一的静态(类方法)访问方式,并封锁了这个类外部的代码对这个类对象的创建。

.h文件:

 #import <Foundation/Foundation.h>

 @interface Singleton : NSObject
@property (nonatomic, copy) NSString *name;
+ (Singleton *) sharedInstance;
@end

这里定义了一个类方法来获取单例对象的实例。

.m文件则比较复杂,首先要负责这个对象的创建:

 #import "Singleton.h"

 @implementation Singleton

 static Singleton *_sharedInstance = nil;
+ (Singleton *) sharedInstance {
if (_sharedInstance == nil) {
_sharedInstance = [[super allocWithZone:nil] init];
}
return _sharedInstance;
} +(id)allocWithZone:(struct _NSZone *)zone {
return [[self sharedInstance] retain];
}

这里令人费解的是红字部分,为什么不直接alloc一个Singletone呢?

其实allocWithZone:nil就等价于alloc,只是这里alloc的是父类NSObject,这样做目的是把子类Singleton的allocWithZone拆解出去,拆解出来是为了复写。

之所以要复写,是为了堵住内存分配的漏洞,因为除了+sharedInstance方法之外,用户还可能在外部程序当中alloc一个Singleton对象,而OC语言并不支持java/C#当中的将构造函数私有化。

所以,子类复写allocWithZone的目的就显而易见、无需多言了。

到这里还没有结束,还需要堵住其他内存管理的漏洞,一是保证直接alloc的结果和使用sharedInstance方法的效果一样,二是令release无效:

 -(id)copyWithZone:(NSZone *)zone {
return self;
} -(id)init {
if (_sharedInstance) {
return _sharedInstance;
}
self = [super init];
return self;
} - (id)retain {
return self;
} -(void)release {
// Do nothing
} -(id)autorelease {
return self;
} -(NSUInteger)retainCount {
return NSUIntegerMax;
}

这样就形成了一个中规中矩的、满足内存管理的单例模式,代码显得十分啰嗦,本质原因在于OC对private支持的不好,导致我们做了很多额外工作。

上面的代码不是线程安全的,如果需要保证单例对象的线程安全性,则需要写同步锁代码。

ARC下的单例相对简单:

 + (id)sharedInstance
{
static dispatch_once_t pred = ;
__strong static id _sharedObject = nil;
dispatch_once(&pred, ^{
_sharedObject = [[self alloc] init]; // or some other init method
});
return _sharedObject;
}

更有甚者搞了一个宏:http://lukeredpath.co.uk/blog/2011/07/01/a-note-on-objective-c-singletons/

MRC下单例模式的内存问题与ARC实现的更多相关文章

  1. iOS: ARC & MRC下string内存管理策略探究

    ARC & MRC下string内存管理策略探究 前两天跟同事争论一个关于NSString执行copy操作以后是否会发生变化,两个人整了半天,最后写代码验证了一下,发现原来NSString操作 ...

  2. 1.ARC下是否有内存溢出等问题 2.@property参数 3.#import和@class的区别

    1.ARC下是否有内存溢出等问题? 答案:必须要担心啊,ARC也不是万能的.答案:必须要担心啊,ARC也不是万能的.这里主要是涉及到集合类的数据类型   比如数组,我们定义了一个可变数组muarr1, ...

  3. OC的内存管理(二)ARC

    指针: 指向内存的地址指针变量 存放地址的变量指针变量值 变量中存放的值(地址值)指针变量指向的内存单元值 内存地址指向的值1):强指针:默认的情况下,所有的指针都是强指针,关键字strong ):弱 ...

  4. linux 下 取进程占用内存(MEM)最高的前10个进程

    # linux 下 取进程占用 cpu 最高的前10个进程ps aux|head -1;ps aux|grep -v PID|sort -rn -k +3|head # linux 下 取进程占用内存 ...

  5. Linux 下增大tomcat内存

    我的服务器的配置: # OS specific support.  $var _must_ be set to either true or false. JAVA_OPTS="-Xms10 ...

  6. 32位Windows7上8G内存使用感受+xp 32位下使用8G内存 (转)

    32位Windows7上8G内存使用感受+xp 32位下使用8G内存 博客分类: Windows XPWindowsIE企业应用软件测试  我推荐做开发的朋友:赶快加入8G的行列吧....呵呵..超爽 ...

  7. (转)Linux下tomcat JVM内存设置步骤

    java.lang.OutOfMemoryError: PermGen space java.lang.OutOfMemoryError: Java heap space -------------- ...

  8. [转帖]linux下CPU、内存、IO、网络的压力测试,硬盘读写速度测试,Linux三个系统资源监控工具

    linux下CPU.内存.IO.网络的压力测试,硬盘读写速度测试,Linux三个系统资源监控工具 https://blog.51cto.com/hao360/1587165 linux_python关 ...

  9. iOS下单例模式实现(一)(objective-c arc gcd)

    单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 这里主要介绍下在arc下,利用gcd实现单例. 第一步:声明一个静态实例 static SoundTool *_instan ...

随机推荐

  1. uvalive 6888 Ricochet Robots bfs

    题目链接 给一个n*m的图, 图上有n个标号, n<=4, 然后有墙, 还有一个终点x. 每一步, 只能走某一个标号, 可以向四个方向走, 然后必须要碰到墙或者图的边界或者另一个标号才能停下来. ...

  2. warning: control reaches end of non-void function

    用gcc编译一个程序的时候出现这样的警告: warning: control reaches end of non-void function 它的意思是:控制到达非void函数的结尾.就是说你的一些 ...

  3. 9.java.lang.ClassCastException

    java.lang.ClassCastException 数据类型转换异常 当试图将对某个对象强制执行向下转型,但该对象又不可转换又不可转换为其子类的实例时将引发该异常,如下列代码. Object o ...

  4. Oracle EBS-SQL (INV-2):库存会计期间.sql

    SELECT STATUS, PERIOD_NAME, PERIOD_NUMBER, PERIOD_YEAR, START_DATE, END_DATE, CLOSE_DATE, REC_TYPE,  ...

  5. INFOQ几篇论文

    http://www.infoq.com/cn/articles/java-profiling-with-open-source http://www.infoq.com/cn/articles/Vi ...

  6. iOS6和iOS7代码的适配(4)——tableView

    iOS7上不少控件的样子有了变化(毕竟要扁平化嘛),不过感觉变化最大的肯定非tableView莫属.因为这个控件的高度可定制性,原先是使用及其广泛的,这样的一个改变自然也影响颇大. 1.accesso ...

  7. poj2231---暴力

    #include<stdio.h> #include<stdlib.h> #include<math.h> ]; int cmp(const void *a,con ...

  8. VS2012 TFS切换账号登录

    最近要做团队项目,用到的vs2012的tfs代码管理器(win7 +vs2012),切换账号的流程如下: 1.打开控制面板,进入用户账户 2.点击左侧的管理您的凭据,看到自己的TFS服务器的地址,然后 ...

  9. ServiceStack 入门(二)

    本文介绍创建一个简单的基于ServiceStack的项目. 1. 新建一个solution 2.创建完成后有4个project. ServiceModel是定义Request DTO 和 Reques ...

  10. Ubuntu - Dconf 注册表键值修改参考表

    gsettings reset org.gnome.desktop.wm.preferences theme默认gnomegsettings set org.gnome.desktop.interfa ...