iOS设计模式之单例模式

866 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情

  • 本文主要介绍iOS设计模式中单例模式的介绍,单例模式是我们平时使用比较多的一种设计模式,提供了对类的对象所提供的资源的全局的访问点,因此我们可以使用单例返回的对象进行传递值等。

1. 什么是单例模式

单例模式是设计模式的最简单的形式了。这一模式的意图是使得类的一个对象成为系统中的唯一实例。我们通常会使用类方法返回实例对象,因此我们可以使用工厂方法进行实现改类在程序中只实例化一次。该方法我们首先判读是否存在实例,不存在的话进行实例之后返回该实例。
在数学中。singleton指“单元素集合”,指仅由一个元素组合成的集合。

单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

2. 什么时候使用单例模式

  • 只能有一个实例,而且必须从一个为人熟知的访问点对其进行访问,比如工厂方法。
  • 这个唯一的实例只能通过子类化进行拓展,而且拓展的对象不会破坏客户端代码。 单例模式提供了一个为人熟知的访问点,提供客户类为共享资源生成唯一实例,并通过它对共享资源进行访问,虽然静态的全局对象引用或类方法也可以提供全局访问点,但是全局对象无法防止类被实例化一次以上,而且类方法也缺少消除耦合的灵活性
    比如我们APP中保存用户的信息类,UserModel的信息在全局中多次被用到,同时我们只要一次实例化,这个时候使用单例模式就可以提供了灵活性。或者是网络请求的工具类我们实例化一次,全局都可以使用。

3. 在Cocoa Touch中使用单例模式

我们在开发中会发现大量的单列类,这里简单的介绍下UIApplicationNSFileManager

3.1 UIApplication

每个iOS应用程序都恰好有一个UIApplication实例(或很少是UIApplication的子类)。当应用程序启动时,系统调用UIApplicationMain(_:_:_:_:)函数。除其他任务外,此函数创建一个单例UIApplication对象,您可以使用shared访问。
UIApplication对象为应用程序处理许多内务管理任务,包括传入的用户事件的最初路由,以及为UIController分发动作消息给合适的目标。并且还维护应用程序中打开所有UIWindow对象的列表。应用程序对象总是被分配给一个UIApplicationDelegate对象,把运行时事件通知给她。

3.2 NSFileManager

文件管理器对象允许您检查文件系统的内容并对其进行更改。NSFile类提供了对共享文件管理器对象的便捷访问,该对象适用于大多数类型的文件相关操作。文件管理器对象通常是您与文件系统交互的主要模式。您使用它来定位、创建、复制和移动文件和目录。您还可以使用它来获取有关文件或目录的信息或更改其某些属性。
可以通过defaultManager进行访问,但是可能会存在线程安全问题。
可以从多个线程安全地调用共享NSFile对象的方法。但是,如果您使用委托接收有关移动、复制、删除和链接操作状态的通知,您应该创建文件管理器对象的唯一实例,将委托分配给该对象,并使用该文件管理器启动操作。

4. 代码展示

单利通常有2种写法,第一种:

static Network *_network;

+(instancetype)share

{

    if (!_network) {

        _network = [[Network alloc]init];

    }

    return _network;

}

这样写会在多线程情况下导致重复创建,不安全。通常会添加一个同步锁

+(instancetype)share

{

    @synchronized (self) {

        if (!_network) {

            _network = [[Network alloc]init];

        }

    }

    return _network;

}

继续优化下,防止每次读取造成卡顿,外面在加一层判断。

+(instancetype)share

{

   if (!_network) {

        @synchronized (self) {

            if (!_network) {

                _network = [[Network alloc]init];

            }

        }

    }

    return _network;

}

第二种:看下GCD单例写法

static Network *_network;

+(instancetype)shareInstance
{
    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        _network = [[Network alloc]init];

    });


    return _network;

}

当然为了防止alloccopy导致实例化我们通常也会实现allocWithzonecopyWithZone,用来确定唯一性。

5. 总结

单例模式在我开发生涯中,使用的比较多,但是大量的单例模式使用会造成内存长期处于无法释放的状态,虽然解决了我们传值状态保存等方便性。但是它违返了单一职责原则。单例模式可能掩盖不良设计, 比如程序各组件之间相互了解过多等。