iOS singleton pattern

  1. The role of the singleton mode
    can ensure that during the running process of the program, there is only one instance of a class, and the instance is easy to be accessed by the outside world,
    which conveniently controls the number of instances and saves system resources.

  2. The singleton pattern is used
    in the entire application, sharing a resource (this resource only needs to be created and initialized once), which is generally used for tool classes. For example: login controller, network data request, music player, etc. A project needs to use multiple controllers or methods.

  3. Advantages and disadvantages of singleton mode
    Advantages:
    The singleton mode can ensure that there is only one instance of a class in the system and the instance is easily accessible to the outside world, thereby facilitating the control of the number of instances and saving system resources.
    If you want to have only one object of a certain class in the system, the singleton pattern is the best solution.
    Singleton pattern Because the class controls the instantiation process, the class can modify the instantiation process more flexibly.

    Disadvantages:
    Once the singleton object is created, the object pointer is stored in the static area, and the memory space allocated by the singleton object in the heap will not be released until the application terminates.
    Singleton classes cannot be inherited, so it is difficult to extend classes.
    Singletons are not suitable for changing objects. If objects of the same type always change in different use case scenarios, singletons will cause data errors and cannot save each other's state.

Note: Before we use the singleton class, we must consider whether the singleton class is suitable and the future extensibility of the class, so as to avoid blind abuse of the singleton class

 

Singleton implementation steps in ARC

 

1 Provide a static modified global variable inside the class
2 Provide a class method for easy access to the outside world
3 Rewrite the +allocWithZone method to ensure that memory space is always allocated only once for the singleton object
4 For the sake of rigor, rewrite the -copyWithZone method and - MutableCopyWithZone method singleton code implementation in ARC

#import "Tools.h"

@implementation Tools
// 创建静态对象 防止外部访问
static Tools *_instance;
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
//    @synchronized (self) {
//        // 为了防止多线程同时访问对象,造成多次分配内存空间,所以要加上线程锁
//        if (_instance == nil) {
//            _instance = [super allocWithZone:zone];
//        }
//        return _instance;
//    }
    // 也可以使用一次性代码
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (_instance == nil) {
            _instance = [super allocWithZone:zone];
        }
    });
    return _instance;
}
// 为了使实例易于外界访问 我们一般提供一个类方法
// 类方法命名规范 share类名|default类名|类名
+(instancetype)shareTools
{
    //return _instance;
    // 最好用self 用Tools他的子类调用时会出现错误
    return [[self alloc]init];
}
// 为了严谨,也要重写copyWithZone 和 mutableCopyWithZone
-(id)copyWithZone:(NSZone *)zone
{
    return _instance;
}
-(id)mutableCopyWithZone:(NSZone *)zone
{
    return _instance;
}

3. Implementation of singleton in MRC

MRC singleton implementation steps

1 在类的内部提供一个static修饰的全局变量
2 提供一个类方法,方便外界访问
3 重写+allocWithZone方法,保证永远都只为单例对象分配一次内存空间
4 严谨起见,重写-copyWithZone方法和-MutableCopyWithZone方法
5 重写release方法
6 重写retain方法
7 建议在retainCount方法中返回一个最大值

配置MRC环境

1 注意ARC不是垃圾回收机制,是编译器特性
2 配置MRC环境:build setting ->搜索automatic ref->修改为N0

MRC中单例代码实现
配置好MRC环境之后,在ARC代码基础上重写下面的三个方法即可

-(oneway void)release
{

}
-(instancetype)retain
{
    return _instance;
}
-(NSUInteger)retainCount
{
    return MAXFLOAT;
}

四. 一劳永逸,单例模式的优化

如果想要一劳永逸,我们将面临两个问题
1:如何写一份单例代码在ARC和MRC环境下都适用?
2:如何使一份单例代码可以多个类共同使用
为了解决这两个问题,我们可以在PCH文件使用代参数的宏和条件编译
利用条件编译来判断是ARC还是MRC环境

#if __has_feature(objc_arc)
//如果是ARC,那么就执行这里的代码1
#else
//如果不是ARC,那么就执行代理的代码2
#endif

注意:单例模式不可以使用继承,因为使用继承,同时也会继承静态变量,当子类和父类同时创建的时候只会创建一个先创建的实例对象。
废话不多说了直接上代码
PCH文件Single.h

#define singleH(name) +(instancetype)share##name;

#if __has_feature(objc_arc)

#define singleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
    static dispatch_once_t onceToken;\
    dispatch_once(&onceToken, ^{\
        _instance = [super allocWithZone:zone];\
    });\
    return _instance;\
}\
\
+(instancetype)share##name\
{\
    return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone\
{\
    return _instance;\
}\
\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
    return _instance;\
}
#else
#define singleM static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
return _instance;\
}\
\
+(instancetype)shareTools\
{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
-(oneway void)release\
{\
}\
\
-(instancetype)retain\
{\
    return _instance;\
}\
\
-(NSUInteger)retainCount\
{\
    return MAXFLOAT;\
}
#endif

这时我们就可以一劳永逸,任何项目中,当我们要使用单例类的时候只要在项目中导入PCH文件然后
在.h文件中调用singleH(类名)
在.m文件中调用singleM(类名)
创建类时直接调用share类名方法即可。

@implementation WMSVoicePickingController
static WMSVoicePickingController *sharedVoicePickingController = nil;

+(WMSVoicePickingController *)shareVoicePicking{
    if (sharedVoicePickingController == nil) {
        sharedVoicePickingController = [[WMSVoicePickingController alloc] init];
    }
    return sharedVoicePickingController;
}

+(void)cleanVoicePicking{
    if (sharedVoicePickingController) {
        sharedVoicePickingController = nil;
    }
}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326252488&siteId=291194637