在最初进行OC的学习时笔者了解过单例模式的基本使用,现撰写博客加深对单例模式的理解
单例模式是一种常见的设计模式,其主要目的是确保一个类只有一个实例,并提供全局访问点。这样就大大节省了我们的内存,防止一个实例被重复创建从而占用内存空间。这种模式在需要一个共享资源或对象的情况下非常有用,但也有一些优点和缺点。
面向对象应用程序中的单例类(singleton class)总是返回自己的同一个实例。它提供了对象所提供的资源的全局访问点。与这类设计相关的设计模式称为单例模式。
大家在开发过程中也见过不少的单例,比如UIApplication、UIAccelerometer(重力加速)、NSUserDefaults、NSNotificationCenter,当然,这些是开发Cocoa Touch框架中的,在Cocoa框架中还有NSFileManager、NSBundle等。
懒汉模式(Lazy Initialization)是一种常见的单例设计模式,其主要特点是在需要时才会创建单例对象的实例,而不是在程序启动时就立即创建。懒汉模式通过延迟对象的初始化来节省资源和提高性能。
举个简单的例子,你现在有衣服要洗,但是可以选择先不洗,等没衣服穿的时候再洗,这就是懒汉模式的逻辑——==需要用到实例时再去创建实例。
我们给出懒汉模式的代码:
ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController<NSCopying, NSMutableCopying>
+ (instancetype)shareSingleton;
@end
ViewController.m
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
static id _instance;
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
if (_instance == nil) {//互斥锁防止被频繁加锁
@synchronized (self) {
if (_instance == nil) {//防止单例被多次创建
_instance = [super allocWithZone:zone];
}
}
}
return _instance;
}
+ (instancetype)shareSingleton {
if (_instance == nil) { //防止被频繁枷锁
@synchronized (self) {
if (_instance == nil) {
_instance = [[self alloc] init];
}
}
}
return _instance;
}
- (void)viewDidLoad {
[super viewDidLoad];
_instance = [[NSString alloc] init];
_instance = @"111";
NSLog(@"%@", _instance);
}
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
return _instance;
}
- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
return _instance;
}
//copyWithZone: 和 mutableCopyWithZone: 方法是用于复制对象的方法。在这里,它们都被重写为返回单例对象的引用 _instance,以确保复制操作也得到同一个单例对象的引用,而不会创建新的对象副本。
@end
使用懒汉模式时我们有几个问题值得我们讨论:
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
if (_instance == nil) {//互斥锁防止被频繁加锁
@synchronized (self) {
_instance = [super allocWithZone:zone];
}
}
return _instance;
}
答案是不行的,因为我们只是锁住了对象的创建,如果两个线程同时进入if,那么就会产生两个对象
如果我们不使用static,其他类中可以使用extern来拿到这个单例
extern id instance;
instance = nil;
如果在其他类中对单例进行如下操作,那么单例就会被重新创建,我们原本的单例对象中的内容就被销毁了。
具体用法可以参考这篇博客:【iOS】浅析static,const,extern关键字
通过代码可以看到我们的allocWithZone与shareSingleton方法是相同的,我们既可以通过shareSingleton创建单例,也可以通过allocWithZone创建单例。
copyWithZone: 和 mutableCopyWithZone: 方法是用于复制对象的方法。在这里,它们都被重写为返回单例对象的引用 _instance,以确保复制操作也得到同一个单例对象的引用,而不会创建新的对象副本。
在没有使用代码去创建对象之前,这个对象已经加载好了,并且分配了内存空间,当你去使用代码创建的时候,实际上只是将这个原本创建好的对象拿出来而已。
通俗的理解就是我们可以选择一回家就吃饭,也可以选择回家后躺一会再吃,躺一会再吃就是懒汉模式,直接吃就是饿汉模式
在我们的类加载过程中我们的单例就已经被创建了,我们无需在后面再去创建,直接使用即可
这里给出代码示例:
ehanViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface ehanViewController : UIViewController<NSMutableCopying, NSCopying>
//获取单例
+ (instancetype)sharedSingleton;
@end
NS_ASSUME_NONNULL_END
ehanViewController.m
#import "ehanViewController.h"
@interface ehanViewController ()
@end
@implementation ehanViewController
static id _instance;
//当类加载到OC运行时环境中(内存),就会调用一次(一个类之后加载一次)
+ (void)load {
_instance = [[self alloc] init];
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
if (_instance == nil) { //防止创建多次
_instance = [super allocWithZone:zone];
}
return _instance;
}
+(instancetype)sharedSingleton {
return _instance;
}
- (void)viewDidLoad {
[super viewDidLoad];
_instance = @"111";
NSLog(@"%@", _instance);
}
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
return _instance;
}
- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
return _instance;
}
@end
懒汉模式:
饿汉模式:
总的来说,懒汉模式适用于需要延迟加载实例的情况,可以节省资源和提高性能,但需要考虑线程安全性。饿汉模式适用于需要简单实现和线程安全性的情况,但不支持延迟加载。选择哪种模式应根据具体需求和性能考虑来决定。