iOS 设计模式: Singleton – 单例模式

单例 的意思就是确保在程序运行过程中只创建一个对象实例,而可以被多次使用。如我们常见的网络请求类、工具类、和其他管理类等。作为一个iOS开发者,我们经常和单例打交道,比如:[NSUserDefaults standerUserDefaults], [UIApplication sharedApplication],[UIScreen mainScreen], [NSFileManager defaultManager]返回的都是单例对象。
我们在开源项目、苹果示例代码能见到无数使用单例的例子。Xcode 甚至有默认的 "Dispatch Once" 代码片段,使我们可以非常简单地在代码中添加一个单例。

"Dispatch Once" 代码片段

一、单例的作用

  • 它可以保证某个类在程序运行过程中最多只有一个实例,节省内存开销。如果某个对象需要被多个其它对象使用,那可以考虑使用单例,因为这样该类只使用一份内存资源。

注意点!!!! 单例应该只用来保存全局的状态,并且不能和任何作用域绑定。如果这些状态的作用域比一个完整的应用程序的生命周期要短,那么这个状态就不应该使用单例来管理。因为单例从创建后到彻底关闭程序前都会一直存在,如果过多的创建单例无疑浪费系统资源和影响系统效率

二、单例的三要点

  • 单例模式的三个要点:

1. 该类有且只有一个实例;(类的构造方法是私有的我们只需要重写allocWithZone方法,让初始化操作只执行一次)

2. 该类必须能够自行创建这个实例;(类提供一个类方法产生对象)

3. 该类必须能够自行向整个系统提供这个实例。(类中有一个私有的自己对象我们可以在.m文件中定义一个属性即可)

三、单例的实现步骤

1. 为单例对象创建一个静态实例,可以写成全局的,也可以在类方法里面实现,并初始化为nil;
  2. 提供一个类方法,方便外界访问;
  3. 重写allocWithZone方法,用来保证其他人直接使用alloc和init试图获得一个新实力的时候不产生一个新实例;
  4. 重写-copyWithZone方法和-MutableCopyWithZone方法

一般创建对象的步骤分为申请内存(alloc)、初始化(init)这两个步骤,我们要确保对象的唯一性,所以要在第一步拦截它。当我们调用alloc方法时,oc内部会调用allocWithZone这个方法来申请内存,我们覆写这个方法,然后在这个方法中调用shareInstance方法返回单例对象,这样就可以达到我们的目的。拷贝对象也是同样的原理,覆写copyWithZone方法,然后在这个方法中调用shareInstance方法返回单例对象。

#import "Tools.h"

@implementation Tools
// 创建静态对象 防止外部访问
static Tools *_instance;
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
    @synchronized (self) {
        // 为了防止多线程同时访问对象,造成多次分配内存空间,所以要加上线程锁
        if (_instance == nil) {
           _instance = [super allocWithZone:zone];
      }
      return _instance;
}
// 为了使实例易于外界访问 我们一般提供一个类方法
// 类方法命名规范 share类名|default类名|类名
+(instancetype)shareTools
{
    //return _instance;
    // 最好用self 用Tools他的子类调用时会出现错误
    return [[self alloc]init];
}
// 为了严谨,也要重写copyWithZone 和 mutableCopyWithZone
-(id)copyWithZone:(NSZone *)zone
{
    return _instance;
}
-(id)mutableCopyWithZone:(NSZone *)zone
{
    return _instance;
}

也可以使用Xcode 默认的dispatch_once代码片段用 GCD的方式创建:
@implementation Singleton
static id _instance;

+ (instancetype)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}

+ (instancetype)sharedSingleton{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}

- (id)copyWithZone:(NSZone *)zone{
    return _instance;
}
@end

四、使用单例的注意事项

  • 单例给我们带来方便的同时也有一定的副作用,因为单例对象一旦创建,对象指针是保存在静态区的,单例对象在堆中分配的内存空间只有在程序终止后才会释放,过多的单例必定会增大我们消耗的内存
  • 不要做断开单例类对象与类中静态引用的危险操作。
  • 多线程使用单例使用共享资源时,注意线程安全问题。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 单例模式 什么是单例模式? 单例模式想一个大独裁者,他规定在他的国度里面,所有数据的访问和请求都得经过他,甚至你要...
    GitHubPorter阅读 1,191评论 0 4
  • 1 单例模式的动机 对于一个软件系统的某些类而言,我们无须创建多个实例。举个大家都熟知的例子——Windows任务...
    justCode_阅读 1,484评论 2 9
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,014评论 19 139
  • 单例模式(SingletonPattern)一般被认为是最简单、最易理解的设计模式,也因为它的简洁易懂,是项目中最...
    成热了阅读 4,298评论 4 34
  • 前言 本文主要参考 那些年,我们一起写过的“单例模式”。 何为单例模式? 顾名思义,单例模式就是保证一个类仅有一个...
    tandeneck阅读 2,541评论 1 8