【iOS】单例、通知、代理

1 单例模式

1.1 什么是单例

单例模式在整个工程中,相当于一个全局变量,就是不论在哪里需要用到这个类的实例变量,都可以通过单例方法来取得,而且一旦你创建了一个单例类,不论你在多少个界面中初始化调用了这个单例方法取得对象,它们所有的对象都是指向的同一块内存的存储空间(即单例类保证了该类的实例对象是唯一存在的一个)。

1.2 单例模式的优缺点

  • 优点

    • 一个类只被实例化一次,提供了对唯一实例的受控访问。
    • 节省系统资源。
    • 允许可变数目的实例。
  • 缺点

    • 一个类只有一个对象,可能造成责任过重,在一定程度上违背了“单一职责原则”。
    • 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
    • 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

1.3 单例的实现

单例的实现分为两种:懒汉式和饿汉式。

  • 懒汉式:顾名思义,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化。
  • 饿汉式:饿了肯定会饥不择食,所以在单例类加载的时候就进行实例化。

特点和选择:

  • 由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能,这是以空间换时间。
  • 在访问量较小时,采用懒汉实现,这是以时间换空间。

1.3.1 懒汉式

  1. 使用@synchronized
static id manager = nil;
+ (instancetype)shareInstance {
   
	// 防止多次加锁
    if (!manager) {
   
        @synchronized (self) {
   
            if (!manager) {
   
                manager = [[super allocWithZone:NULL] init];
            }
        }
    }
    return manager;
}

第一次if(!manager)判断是为了避免在对象创建后多次访问导致的多次加锁,浪费性能。第二次if(!manager)判断就是判断此时单例是否存在,不存在就重新创建。

  1. 使用GCD
+ (instancetype)shareInstance {
   
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
   
        manager = [[super allocWithZone:NULL] init];
    });
    return manager;
}

dispatch_once它没有使用重量级的同步机制,性能也优于前者,并且更加高效。

dispatch_once无论使用多线程还是单线程,都只执行一次,在安全的前提下也保证了性能。

dispatch_once主要是根据onceToken的值来决定怎么执行代码:

  • onceToken为0时,线程执行dispatch_onceblock中的代码。
  • onceToken为-1时,线程跳过dispatch_onceblock中的代码。
  • onceToken为其他值时,线程被阻塞,等待onceToken值改变。

dispatch_once的执行流程:

  1. 当线程调用shareInstance,此时onceToken为0,执行dispatch_onceblock中的代码,此时onceToken中的值为其他值。
  2. 这时如果有其他线程再调用shareInstance方法时,onceToken值为其他值,线程阻塞。
  3. block线程执行完block后,onceToken变为-1。其他线程不再阻塞,跳过block
  4. 下次再调用shareInstance时,onceToken为-1,直接跳过block

1.3.2 饿汉式

当类被加载的时候就创建,因为一个类在整个生命周期中只会被加载一次,所以它肯定只有一个线程对其进行访问,此时再创建他就是线程安全的,就不需要使用线程锁来保证其不会被多次创建。

static id manager = nil;

+ (void)load {
   
    [super load];
    manager = [[super allocWithZone:NULL] init];
}

+ (instancetype)shareInstance {
   
    return manager;
}

- (instancetype)copyWithZone:(NSZone *)zone {
   
    return manager;
}

- (instancetype)mutableCopyWithZone:(NSZone *)zone {
   
    return manager;
}

+ (instancetype)allocWithZone:
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值