iOS------单例模式

1.单例介绍

单例:该类在程序运行期间有且仅有一个实例。
为了我们能更好的理解单例模式,我列举以下几个cocoa框架中常用的单例:

1.UIApplication:应用程序。一个UIApplication对象就代表着一个应用程序,每个应用程序有且仅有一个UIApplication对象,开发中最常用的是使用它的openURL函数来跳转到其他应用程序,通过
[UIApplication sharedApplication] 类方法可以获得。

2.NSNotificationCenter:通知中心。iOS中的通知中心是一种消息广播,采用观察者模式和单例模式,一个应用有且仅有一个通知中心。通过
[NSNotificationCenter defaultCenter] 类方法可以获得。

3.NSFileManager:文件管理器。它是iOS文件系统的接口,用来创建、修改、访问文件。一个应用有且仅有一个文件管理器。通过 [NSFileManager defaultManager] 类方法可以获得。

4.NSUserDefaults:用户偏好设置。它主要用来存储简单的键值对数据,数据持久化最简单和基础的一种方案。通过 [NSUserDefaults standardUserDefaults] 类方法可以获得。

5.NSURLCache:URL缓存。通过将NSURLRequest对象映射到NSCachedURLResponse对象来实现对URL加载请求的响应的缓存。
通过 [NSURLCache sharedURLCache] 类方法可以获得.

1.1单例模式的要点
1.该类有且只有一个实例;
2.该类必须能够自行创建这个实例;
3.该类必须能够自行向整个系统提供这个实例;

1.2单例的主要优点
1.单例可以保证系统中该类有且仅有一个实例。确保所有对象都访问这个唯一实例;
2.因为类控制了实例化对象,所以类可以灵活更改实例化过程;
3.基于第一条,对于项目中的个别场景的传值,存储状态等业务更加方便;
4.可以节约系统资源,对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能;

1.3单例的主要缺点
1.由于单例模式没有抽象层,因此单例类的扩展有很大的困难。单例不能被继承,不能有子类。
2.不易被重写或扩展 (可以使用分类)
3.单例实例一旦创建,对象指针是保存在静态区,那么在堆区分配的空间只能在应用程序终止才会被释放;
4.单例类的指责过重,在一定程度上违背了“单一职责的原则”;

2.单例的生命周期

首先复习一下内存的五大存储区域
在这里插入图片描述

在程序中,一个单例类在程序中只能初始化一次,为了保证在使用中始终都是存在的,所以单例是在存储器的全局区域,在编译时分配内存,只要程序还在运行就会一直占用内存,在app结束后有系统释放这部分内存。

单例的静态变量被指为nil是否内存会得到释放?
将单例类实例对象赋值为nil后,会触发单例的dealloc方法,静态变量修饰的指针保存在了全局区域,不会释放。但指针保存的首地址关联的对象是保存在堆区的,是会释放的。
单例的实现

关键字static
1.static修饰局部变量

普通的局部变量创建后是放在栈区中,这种局部变量进入作用域时创建,出了作用域就销毁,并且只初始化一次。static修饰局部变量这放在静态区中,它改变了局部变量的存储位置,从而使它的生命周期延长,直至程序结束才销毁

static修饰局部变量只改变生命周期,不改变作用域。

2.static修饰全局变量

全局变量存储在静态区,它的作用域十分的广,只要在一个源文件中定义后,这个程序中的所有源文件、对象以及函数都可以调用,生命周期更是贯穿整个程序。文件中的全局变量想要被另一个文件使用时就需要进行外部声明(以下用extern关键字进行声明)。其本质是:全局变量本身是具有外部链接属性的,在A文件中定义的全局变量,在B文件中可以通过【链接】来使用;

当static修饰全局变量,那这个外部链接属性就会被修改成内部链接属性,此时这个全局变量就只能在自己的源文件中使用,就无法在另一个文件用extern关键字声明使用。

static修饰全局变量不改变生命周期,单缩小了作用域。

这里用static修饰单例,防止在其他类中通过extern关键字声明对单例进行修改。

单例的实现重点就是防止在外部调用的时候出现多个不同的实例,也就是在创建的方式入手禁止出现多个不同的实例
主要做到以下几点:

1.防止调用 [[A alloc] init] 引起错误

2.防止调用 new 引起错误

3.防止调用 copy 引起错误

4.防止调用 mutableCopy 引起错误

典型的单例写法

static id instance  = nil;
+(id) crestInstance {
  //如果全区变量为nil
  if (!instance) {
  //创建一个实例,并将该实例赋给instance全区变量
   instance = [[self alloc] init];
  }
  retrurn instance
}

缺点:无法保证多线程情况下只创建一个对象。适用于单线程。
加锁的方法

 static Singleton *_sharedSingleton = nil;
 
+(instancetype)sharedSingleton {
    @synchronized(self){   //加锁,保证多线程下也只能有一个线程进入
        if (! _sharedSingleton) {
            _sharedSingleton = [[self alloc] init]; 
        } 
    } 
    return _sharedSingleton;
 }

免锁的方法

static Singleton *_sharedSingleton = nil;
 
+ (instancetype)sharedSingleton {
    static BOOL initialized = NO;//确保只有在第一次调用sharedSingletion方法才会创建实例。在后续调用时,直接返回之前创建的实例,避免重复创建。
    if (initialized == NO){
        initialized = YES;
        _sharedSingleton = [[self alloc] init];
    }
    return _sharedSingleton;
 }

3.单例模式的类型
懒汉模式:在真正需要使用对象时才去创建该单例类对象
饿汉模式:在类加载时已经创建好该单例对象,等待程序使用;

懒汉模式创建单例对象是在程序使用对象前,先判断对象是否实例化(判空),若已实例化直接返回该类对象,否者先执行实例化操作。
在这里插入图片描述

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Singletion : NSObject<NSMutableCopying, NSCopying>
+ (instancetype)sharedSingletion;

@end

NS_ASSUME_NONNULL_END

#import "Singletion.h"

@implementation Singletion
static id _instance;
//alloc方法内部会调用这个方法
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    if (_instance == nil) { //防止频繁加锁
        @synchronized (self) {
            if (_instance == nil) { //防止创建多次
                _instance = [super allocWithZone: zone];
            }
        }
    }
    return _instance;
}
//直接调用类方法
+ (instancetype)sharedSingletion {
    if (_instance == nil) {
        @synchronized (self) {
            if (_instance == nil) {
                _instance = [[self alloc] init];
            }
        }
    }
    return _instance;
}
//copy方法内部会调用这个方法
- (id)copyWithZone:(NSZone *)zone {
    return _instance;
}
//mutablecopy方法会调用这个方法
- (id)mutableCopyWithZone:(NSZone *)zone {
    return _instance;
}
@end

@synchronized的作用是创建一个互斥锁,保证此时没有其他线程对self对象进行修改,保证代码的安全性。也就是包装这段代码的原子性的,安全的。这个是OC的一个锁定令牌,防止self对象在同一时间内被其他线程访问,起到保护线程安全的作用。

copyWithZone:和mutableCopyWithZone:是对自定义对象copy和mutableCopy时会用到,这里重写以确保复制操作也得到同一单例对象的引用,而不会创建新的对象副本。

饿汉式创建单例对象,在类加载时已经创建好该对象,在程序调用时直接返回该单例对象即可,即我们在编码时就已经指明了要马上创建这个对象,不需要等到被调用时再去调用
在这里插入图片描述

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface singletion_ehan : NSObject<NSMutableCopying, NSCopying>
+ (instancetype)sharedSingletion;
@end

NS_ASSUME_NONNULL_END


#import "singletion ehan.h"

@implementation singletion_ehan
static id _instance;
//当类加载到OC运行时环境中(内存),就会调用一次(一个类只会加载一次)
+ (void)load {
    _instance = [[self alloc] init];
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    if (_instance == nil) {//防止多次创建
        _instance = [super allocWithZone:zone];
    }
    return _instance;
}
+ (id)sharedSingletion {
    return _instance;
}
- (id)copyWithZone:(NSZone *)zone {
    return _instance;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
    return _instance;
}
@end```

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值