OC单例模式详解

单例模式

有时候我们需要一个全局的对象,而且要保证全局有且仅有一份即可,这时候就需要用到单例设计模式,但是需要注意的是:在多线程的环境下也需要做好线程保护。其实系统已经有很多单例存在,例如UIApplication、NSNotification、NSFileManager、NSUserDefaults等.以下代码详解

ARC环境下严谨的单例模式

#import <Foundation/Foundation.h>
@interface JHTool : NSObject<NSCopying,NSMutableCopying>
//类方法
//1.方便访问
//2.标明身份
//3.注意:share+类名|default + 类名 | share | default | 类名
+(instancetype)shareTool;
@end
#import "JHTool.h"
@implementation JHTool
//提供一个全局静态变量
static JHTool * _instance;

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

//当调用alloc的时候会调用allocWithZone
+(instancetype)allocWithZone:(struct _NSZone *)zone{
    //方案一:加互斥锁,解决多线程访问安全问题
//    @synchronized(self){//同步的
//        if (!_instance) {
//            _instance = [super allocWithZone:zone];
//        }
//    }
    //方案二.GCD dispatch_onec,本身是线程安全的,保证整个程序中只会执行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}
//严谨
//遵从NSCopying协议,可以通过copy方式创建对象
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
    return _instance;
}
//遵从NSMutableCopying协议,可以通过mutableCopy方式创建对象
- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
    return _instance;
}
@end
#import "ViewController.h"
#import "JHTool.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor redColor];
    JHTool * tool1 = [[JHTool alloc]init];
    JHTool * tool2 = [JHTool shareTool];
    JHTool * tool3 = tool1.copy;
    JHTool * tool4 = tool2.mutableCopy;
    NSLog(@"tool1:%p,tool2:%p,tool3:%p,tool4:%p,",tool1,tool2,tool3,tool4);
    printf("tool1:%p,tool2:%p,tool3:%p,tool4:%p,",tool1,tool2,tool3,tool4);

}
@end

打印结果:
ARC

MRC环境下严谨的单例模式

Xcode5以后项目默认都是ARC,所以把项目设置成MRC环境,选择项目 Target -> Build Sttings -> All -> 搜索‘Automatic’ -> 把 Objective-C Automatic Reference Counting 设置为 NO ,如下图:
项目设置成MRC环境
MRC单例模式代码详解

#import <Foundation/Foundation.h>
@interface HJTool : NSObject<NSCopying,NSMutableCopying>
//类方法
+(instancetype)shareTool;
@end
#import "HJTool.h"

@implementation HJTool
//修改环境为MRC:选择项目 Target -> Build Sttings -> All -> 搜索‘Automatic’ -> 把 Objective-C Automatic Reference Counting 设置为 NO
//提供一个静态全局变量
static HJTool * _instance;
//实现类方法
+(instancetype)shareTool{
    return [[self alloc]init];
}
//alloc会调用allocWithZone
+(instancetype)allocWithZone:(struct _NSZone *)zone{
    //方法一.互斥锁保证线程安全
//    @synchronized(self){
//        if (_instance == nil) {
//            _instance = [super allocWithZone:zone];
//        }
//    }
    //方法一.GCD-> dispatch_once_t 该方法只会执行一次,本身线程安全
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}
-(id)copyWithZone:(NSZone *)zone{
    return _instance;
}
-(id)mutableCopyWithZone:(NSZone *)zone{
    return _instance;
}
//MRC特有的
-(instancetype)retain{
    return _instance;
}
-(oneway void)release{
    NSLog(@"%zd",_instance.retainCount);
}
#import "ViewController.h"
#import "HJTool.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor yellowColor];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    HJTool * t1 = [[HJTool alloc]init];
    HJTool * t2 = [[HJTool alloc]init];
    HJTool * t3 = [HJTool shareTool];
    HJTool * t4 = [t1 copy];
    HJTool * t5 = [t2 mutableCopy];
    HJTool * t6 = [t1 retain];
    NSLog(@"t6.retainCount : %zd",t1.retainCount);
    NSLog(@"t1:%p t2:%p t3:%p t4:%p t5:%p t6:%p",t1,t2,t3,t4,t5,t6);
}

打印结果
这里写图片描述

拓展:区分是MRC还是ARC的宏

#if __has_feature(objc_arc)
    //条件满足 ARC,可以处理ARC的代码
    NSLog(@"ARC");
#else
    //条件满足 MRC,,可以处理MRC的代码
    NSLog(@"MRC");
#endif

通用的单例模式

SingleDog.h文件中定义一个宏, SingleH(name)定义单例.h文件的类方法声明,SingleM(name)定义和实现单例.m文件的方法,定义的宏的代码如下

#define SingleH(name) +(instancetype)share##name;//.h文件替换
//.m文件替换
#if __has_feature(objc_arc)//arc
//条件满足 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
//条件满足 MRC
#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;\
}\
-(oneway void)release\
{\
}\
\
-(instancetype)retain\
{\
return _instance;\
}
#endif

单例SingleTool文件,头文件和实现文件分别调用宏的SingleH(name),SingleM(name)即可,代码如下

#import <Foundation/Foundation.h>
#import "SingleDog.h"

@interface SingleTool : NSObject
//替换头文件
SingleH(SingleTool)

@end
#import "SingleTool.h"

@implementation SingleTool
SingleM(SingleTool)
@end
#import "ViewController.h"
#import "SingleTool.h"

@interface ViewController ()

@end

@implementation ViewController

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    SingleTool * t1 = [[SingleTool alloc]init];
    SingleTool * t2 = [SingleTool shareSingleTool];
    SingleTool * t3 = [t1 copy];
    SingleTool * t4 = [t1 mutableCopy];
#if __has_feature(objc_arc)
    //条件满足 ARC,可以处理ARC的代码
    NSLog(@"ARC");
#else
    //条件满足 MRC,,可以处理MRC的代码
    NSLog(@"MRC");
    SingleTool * t5 = [t1 retain];
    NSLog(@"t6.retainCount : %zd",t1.retainCount);
    NSLog(@"t1:%p t2:%p t3:%p t4:%p t5:%p",t1,t2,t3,t4,t5);
#endif
}

@end

MRC环境下打印结果如下:
MRC通用单例模式

猜你喜欢

转载自blog.csdn.net/bolted_snail/article/details/79230097