单例模式用于当一个类只能有一个实例的时候, 通常情况下这个“单例”代表的是某一个物理设备比如打印机,或是某种不可以有多个实例同时存在的虚拟资源或是系统属性比如一个程序的某个引擎或是数据。用单例模式加以控制是非常有必要的。

单例模式需要达到的目的

1. 封装一个共享的资源

2. 提供一个固定的实例创建方法

3. 提供一个标准的实例访问接口

单例模式的创建

简单创建方法:

@interface Singleton : NSObject  

+ (Singleton *) sharedInstance;  

@end  

在Singleton.m

@implementation Singleton    

static Singleton * sharedSingleton = nil;    

+ (Singleton *) sharedInstance  

{  

    if (sharedSingleton == nil) {  

        sharedSingleton = [[Singleton alloc] init];  

    }  

    return sharedSingleton;  

}  

@end  

严谨创建一个MySingletonClass的单例模式。首先,我们需要定义一个类MySingletonClass.

@interface MySingletonClass:NSObject {

}

并且为其添加一个类方法(注意,这里不是实例方法)+(id)sharedInstance;一个基本的实现写法如下:

 static MySingletonClass *sharedCLDelegate = nil;

+(MySingletonClass *)sharedInstance{
@synchronized(self) {
if(sharedCLDelegate == nil) {
[[[self class] alloc] init]; // assignment not done here
}
}
return sharedCLDelegate;
}

在上面的代码中(用到了关键字@synchronized是为了保证我们的单例的线程级别的安全,可以适用于多线程模式下。)static变量sharedCLDelegate用于存储一个单例的指针,并且强制所有对该变量的访问都必须通过类方法   +(id)sharedInstance,在对   +(id)sharedInstance第一次调用时候完成实例的创建。这里值得留意一下的是,上面代码中用的是[[selfclass] alloc],而不是 [MySingletonClass alloc],一般情况下这两种写法产生同样的效果,但是这里这样做是为了更好的利用OOP的性质,[selfclass]可以动态查找并确定类的类型从而便于实现对该类的子类化。

对实例化的控制

为了完全的实现实例的单态性,必须通过一定手段来避免实例多次被创建。+(id)sharedInstance控制了单例的创建和访问,但是并不能控制其它地方的代码通过alloc方法来创建更多的实例,因此我们还要重载任何一个涉及到allocation的方法,这些方法包括   +new, +alloc,+allocWithZone:, -copyWithZone:, 以及 -mutableCopyWithZone:另外,+(id)sharedInstance也需要稍作修改。

+ (id)hiddenAlloc
{
return [super alloc];
}

+ (id)alloc
{
NSLog(@"%@: use +sharedInstance instead of +alloc", [[self class] name]);
return nil;
}

+ (id)new
{
return [self alloc];
}

+(id)allocWithZone:(NSZone*)zone
{
return [self alloc];
}

- (id)copyWithZone:(NSZone *)zone
{ // -copy inherited from NSObject calls -copyWithZone:
NSLog(@"MySingletonClass: attempt to -copy may be a bug.");
[self retain];
return self;
}

- (id)mutableCopyWithZone:(NSZone *)zone
{
// -mutableCopy inherited from NSObject calls -mutableCopyWithZone:
return [self copyWithZone:zone];
}

+(id)sharedInstance修改如下:

+ (MySingletonClass *)sharedInstance {
@synchronized(self) {
if (sharedCLDelegate == nil) {
[[[self class] hiddenAlloc] init]; // assignment not done here
}
}
return sharedCLDelegate;
}

如果不考虑类的子类化,+hiddenAlloc这个方法可以省略。由于我们是用[selfclass]来实现类型的动态识别,用[[selfclass] hiddenAlloc]可以避免调用到被重载过的alloc方法。此外,hiddenAlloc也为可能的子类化提供了一个调用原始alloc方法的机会。上面重载过的alloc方法只是给出一个log信息并且返回nil。Copying方法里只是简单的增加了retain的计数并没有返回一个新的实例。这也正体现了单例模式的性质,因为技术上来讲,拷贝一个单例是错误的(因为是“单例”)所以在copyWithZone方法中我们给出了一个错误信息,当然也可以扔出一个exception。

单例的销毁

通常我们在   -(void)applicationWillTerminate:(UIApplication *)application方法中调用如下方法:

+ (void)attemptDealloc
{
if ([sharedCLDelegate retainCount] != 1)
return;

[sharedCLDelegate release];
myInstance = nil;
}

值得注意的是,上面这个attemptDealloc方法顾名思义,只是试图释放掉这个单例。如果retain的计数不为1,说明还有其他地方对该单例发送过retain消息。考虑到一个单例模式的生存周期是整个程序结束为止。所以,在程序的任何一个地方都没有必要向这个单例发送retain消息,即便是对这个单例有引用。而是调用sharedInstance方法来引用这个单例,这样做是安全的,也是合乎单例模式的技术含义的。

iOS中的单例模式应用

iOS中好几个类都是采用了单例模式,比如NSApplication, NSFontManager,   NSDocumentController,NSHelpManager, NSNull,NSProcessInfo, NSScriptExecutionContext,   NSUserDefaults.

iOS4之后可以这样做

+ (AccountManager *)sharedManager
{
static AccountManager *sharedAccountManagerInstance = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
sharedAccountManagerInstance = [[self alloc] init];
});
return sharedAccountManagerInstance;
}

iOS单例模式的更多相关文章

  1. iOS单例模式(Singleton)写法简析

    单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 1.单例模式的要点: 显然单例模式的要点有三个:一是某个类只能有一个实例: ...

  2. IOS单例模式(Singleton)

    IOS单例模式(Singleton)   单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 1.单例模式的要点: 显然单例模 ...

  3. IOS 单例模式的写法

    iOS的单例模式有两种官方写法,如下: 1)不使用GCD的方式 #import "Manager.h" static Manager *manager; @implementati ...

  4. iOS 单例模式 浅叙

    单例模式作用 可以保证在程序运行过程中,一个类只有一个实例,而且该实例易于供外界使用 从而方便地控制了实例个数,并节约系统资源 单例模式使用场合 在整个引用程序中,共享一份资源(这份资源只需要创建初始 ...

  5. ios 单例模式(懒汉式)

    1. 单例模式的作用 可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问 从而方便地控制了实例个数,并节约系统资源 2. 单例模式的使用场合 在整个应用程序中,共享一份资源(这份资源 ...

  6. IOS 单例模式的学习

    单例模式只能修改无法释放,直到程序结束. 我们下面一步一步来做一个单例模式程序 (1)单例一旦创建,是永远存在于内存中的,所以需要创建一个全局量 static MySingletonClass *sh ...

  7. iOS – 单例模式写一次就够了

    一. 单例模式简介 单例模式的作用 可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问 从而方便地控制了实例个数,并节约系统资源 单例模式的使用场合 在整个应用程序中,共享一份资源( ...

  8. iOS 单例模式简单实例

    单例模式主要实现唯一实例,存活于整个程序范围内,一般存储用户信息经常用到单例,比如用户密码,密码在登录界面用一次,在修改密码界面用一次,而使用单例,就能保证密码唯一实例.如果不用单例模式,init 两 ...

  9. iOS 单例模式 学习 "52个方法 第6章 45条 使用 dispath_once 来执行只需运行一次的线程安全代码"

    百度定义:单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例. 维基百科:在软件工程中,单例是一种用于实现单例的数学概念,即将 ...

随机推荐

  1. Android使用AsyncTask实现可以断点续传的DownloadManager功能

    http://www.it165.net/pro/html/201211/4210.html 最近做项目卡壳了,要做个Android的应用市场,其他方面都还好说,唯独这个下载管理算是给我难住了,究其原 ...

  2. Ubuntu 14.04 LTS 下 android 2.3.5 源码编译过程

    Ubuntu 14.04 LTS 下 android 2.3.5 源码编译过程   在新的Ubuntu 64位系统下去编译早期的安卓源码是会出现很多问题的,因为64位系统在安装完成后,很多32位的兼容 ...

  3. Phaser中很多对象都有一个anchor属性

    游戏要用到的一些图片.声音等资源都需要提前加载,有时候如果资源很多,就有必要做一个资源加载进度的页面,提高用户等待的耐心.这里我们用一个state来实现它,命名为preload. 因为资源加载进度条需 ...

  4. 【转】asp.net c# 网上搜集面试题目大全(附答案)

    asp.net c# 网上搜集面试题目大全(附答案) http://www.cnblogs.com/hndy/articles/2234188.html

  5. Javascript 笔记与总结(2-16)事件对象

    事件对象:事件发生的瞬间,发生位置.时间.鼠标按键.触发的节点等信息,被打包成一个对象,此对象,系统自动传递给事件函数的第一个参数. [例]记录 鼠标划过图片时的事件对象 <!DOCTYPE h ...

  6. Java语言基础相关问题

    *动手动脑: 问题1:   仔细阅读示例: EnumTest.java,运行它,分析运行结果? 源代码: public class EnumTest { public static void main ...

  7. 页面静态化3 --- 使用PHP页面缓存机制来完成页面静态化(下)操作一个案例(新闻管理系统)

    案例需求: 使用PHP缓存机制完成新闻管理系统的页面静态化数据库表 ecs_article (新闻表)因为新闻这些信息,并不是对实时性要求高,本身这个新闻比较稳定,内容也比较固定,所以我们考虑: 当第 ...

  8. Oracle数据库--SQL函数

    Oracle SQL函数  1.ASCII返回与指定的字符对应的十进制数;SQL> select ascii('A') A,ascii('a') a,ascii('0') zero,ascii( ...

  9. the basic index concept

    Computer Science An Overview _J. Glenn Brookshear _11th Edition Over the years numerous variations o ...

  10. Web Storage事件无法触发

    不管是在同源其他页面还是在本页面都不能触发storage事件. <!DOCTYPE html> <html> <head> <meta charset=&qu ...