【iOS】MRC下的单例模式&批量创建单例

单例模式的介绍和ARC下的单例请见这篇:【iOS】单例模式

目录


关闭ARC环境

首先关闭ARC环境,即打开MRC:

或是指定某特定目标文件为非ARC环境:

双击某个类文件,指定为ARC环境,输入-fobjc-arc,指定为MRC环境,输入-fno-objc-arc

MRC下的单例

MRC下,我们就需要手动释放资源,通过重写一些与资源创建与释放相关的方法,以保证单例对象的唯一。

SingletonByMRC.h

objectivec 复制代码
@interface SingletonByMRC : NSObject
+ (instancetype)sharedSingletonByMRC;
@end

SingletonByMRC.m

objectivec 复制代码
@implementation SingletonByMRC

static SingletonByMRC* instanceVariable = nil;

/*
 alloc方法内部会调用allocWithZone:
 参数zone时系统分配给App的内存
 */
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    if (!instanceVariable) {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{  // 安全(这段代码只会被调用一次)
            instanceVariable = [super allocWithZone: zone];
        });
    }
    return instanceVariable;
}

- (oneway void)release {
    //  allocWithZone中使用了GCD命令创建对象的代码只执行一次(单例),如果被释放则无法再创建
    //  重写release方法,替换为空操作,防止instanceVariable被释放
}

//  重写retain方法
- (instancetype)retain {
    return self;
}

//  重写retainCount锁定引用计数
- (NSUInteger)retainCount {
    return 1;
}

//  重写init方法,防止单例所拥有的属性值被重置
//  让初始化的方法只能执行一次,自然属性值就没有机会被重置
- (instancetype)init {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instanceVariable = [super init];
    });
    return instanceVariable;
}

//  仿造系统的单例创建方式,提供类方法
+ (nonnull instancetype)sharedSingletonByMRC {
    // 由于我们已经重写了init方法保证了单例对象的唯一了,所以这里直接调用init方法即可。
    return [[self alloc] init];
}

@end

ARC下的单例

与MRC的主要区别就是不用再手动去释放资源了。

SingletonByARC.m

objectivec 复制代码
#import "SingletonByARC.h"

@implementation SingletonByARC

static SingletonByARC* insVar = nil;

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

- (instancetype)init {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        insVar = [super init];
    });
    return insVar;
}

+ (instancetype)sharedInstance {
    return [[self alloc] init];
}

@end

批量创建单例

如果一个项目中需要多个单例,总不能把上面的代码一个一个复制粘贴再改改就完事了吧?那未免也太麻烦了。

我们可以利用快速且简单地创建单例。

首先先说下一些关于宏的知识:

  • 使用#define关键字来定义宏
  • 宏定义只能是单行的,不能换行

那现在来讨论下一些疑惑吧,你说宏只能单行,可是创建单例的代码可是有很多行呀!还有我们如何做到自定义类方法名(就是 sharedXXX )?我们来介绍下宏下的两个特殊符号:

符号 作用
\ 用来转译换行符,即屏蔽换行符
## 将两个相邻的标记(token)连接为一个单独的标记

简言之,就是\用于取消换行,##用于连接。

创建头文件Singleton.h存放头文件:

objectivec 复制代码
#define SingletonH(methodName) + (instancetype)shared##methodName;

#define SingletonM(methodName) \
static id _instance = nil; \
+ (instancetype)allocWithZone:(struct _NSZone *)zone { \
    if (!_instance) { \
        static dispatch_once_t onceToken; \
        dispatch_once(&onceToken, ^{ \
            _instance = [super allocWithZone:zone]; \
        }); \
    } \
    return _instance; \
} \
\
- (instancetype)init { \
    static dispatch_once_t onceToken; \
    dispatch_once(&onceToken, ^{ \
        _instance = [super init]; \
    }); \
    return _instance; \
} \
\
+ (instancetype)shared##methodName { \
    return [[self alloc] init]; \
}

SingletonH(methodName)为声明宏,SingletonM(methodName)为实现宏。在每一行后面加上(反斜杠)取消换行,使用##来拼接传入的方法名,需要注意的是:最后一行不能加反斜杠。

SingletonClass.h 文件中直接声明shareSingleMethod方法:

objectivec 复制代码
#import "Singleton.h"

@interface SingletonClass : NSObject
SingletonH(SingleMethod);
@end

将方法名SingleMethod传入SingletonH();中就可以拼接为shareSingleMethod

SingletonClass.m直接实现创建单例类

objectivec 复制代码
#import "SingletonClass.h"

@implementation SingletonClass
SingletonM(SingleMethod);
@end

运行结果:

最终我们仅仅用了"两"行代码(SingletonH();SingletonM();),成功创建出了一个单例类,这样是不是节省了大量多余冗杂的代码呢。

Demo

【Github】使用单例进行传值

相关推荐
青花瓷6 小时前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode
2401_865854889 小时前
iOS应用想要下载到手机上只能苹果签名吗?
后端·ios·iphone
HackerTom20 小时前
iOS用rime且导入自制输入方案
ios·iphone·rime
良技漫谈20 小时前
Rust移动开发:Rust在iOS端集成使用介绍
后端·程序人生·ios·rust·objective-c·swift
2401_8524035521 小时前
高效管理iPhone存储:苹果手机怎么删除相似照片
ios·智能手机·iphone
星际码仔1 天前
【动画图解】是怎样的方法,能被称作是 Flutter Widget 系统的核心?
android·flutter·ios
emperinter1 天前
WordCloudStudio:AI生成模版为您的文字云创意赋能 !
图像处理·人工智能·macos·ios·信息可视化·iphone
关键帧Keyframe1 天前
音视频面试题集锦第 8 期
ios·音视频开发·客户端
C++忠实粉丝2 天前
Linux系统基础-多线程超详细讲解(5)_单例模式与线程池
linux·运维·服务器·c++·算法·单例模式·职场和发展
pb82 天前
引入最新fluwx2.5.4的时候报错
flutter·ios