在iOS的开发中,我经常会用到的一种设计模式:单例模式,目的是让这个对象只实例化一次,在内存中只有一份内存。而且是常驻内存,不会被释放。
手写一个单例也许我们都已经很熟悉,但是真的写的很完善吗,有哪些需要注意的呢?
- 全局静态实例对象
- 提供一个供外部调用的类方法
- 加线程锁,防止重复实例化
- 重写内存分配方法
下面我们就在MRC和ARC两种模式下看一下单例的写法有什么区别。
MRC单例
首先我们来看一下手动管理内存时的单例是怎么写的:
头文件MRCSingleton.h
//
// MRCSingleton.h
// Singleton
//
// Created by z on 2019/5/23.
// Copyright © 2019年 com.jzsec. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface MRCSingleton : NSObject <NSCopying,NSMutableCopying>
//给外部提供的类方法
+ (instancetype)shareInstance;
@end
NS_ASSUME_NONNULL_END
实现文件MRCSingleton.m
//
// MRCSingleton.m
// Singleton
//
// Created by z on 2019/5/23.
// Copyright © 2019年 com.jzsec. All rights reserved.
//
#import "MRCSingleton.h"
static MRCSingleton *_instance;
@implementation MRCSingleton
//给外部提供的类方法
+ (instancetype)shareInstance
{
//加互斥锁解决多线程访问安全问题
// @synchronized (self)
// {
// if (_instance == nil)
// {
// _instance = [[MRCSingleton alloc] init];
// }
// }
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[MRCSingleton alloc] init];
});
return _instance;
}
//实例化 分配内存
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
//加互斥锁解决多线程访问安全问题
// @synchronized (self)
// {
// if (_instance == nil)
// {
// _instance = [super allocWithZone:zone];
// }
// }
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
//实现copy协议
-(id)copyWithZone:(NSZone *)zone
{
return _instance;
}
- (id)mutableCopyWithZone:(nullable NSZone *)zone
{
return _instance;
}
- (id)copy
{
return _instance;
}
-(id)mutableCopy
{
return _instance;
}
//覆盖与内存相关的方法
- (instancetype)retain
{
return _instance;
}
- (oneway void)release
{
}
- (NSUInteger)retainCount
{
return UINT_MAX;
}
- (instancetype)autorelease
{
return _instance;
}
@end
ARC单例
自动管理内存时的单例是怎么写的:
头文件ARCSingleton.h
//
// ARCSingleton.h
// Singleton
//
// Created by z on 2019/5/23.
// Copyright © 2019年 com.jzsec. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ARCSingleton : NSObject <NSCopying,NSMutableCopying>
//给外部提供的类方法
+ (instancetype)shareInstance;
@end
NS_ASSUME_NONNULL_END
实现文件ARCSingleton.m
//
// ARCSingleton.m
// Singleton
//
// Created by z on 2019/5/23.
// Copyright © 2019年 com.jzsec. All rights reserved.
//
#import "ARCSingleton.h"
static ARCSingleton *_instance;
@implementation ARCSingleton
//给外部提供的类方法
+ (instancetype)shareInstance
{
//加互斥锁解决多线程访问安全问题
// @synchronized (self)
// {
// if (_instance == nil)
// {
// _instance = [[ARCSingleton alloc] init];
// }
// }
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[ARCSingleton alloc] init];
});
return _instance;
}
//实例化 分配内存
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
//加互斥锁解决多线程访问安全问题
// @synchronized (self)
// {
// if (_instance == nil)
// {
// _instance = [super allocWithZone:zone];
// }
// }
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
//实现copy协议
-(id)copyWithZone:(NSZone *)zone
{
return _instance;
}
- (id)mutableCopyWithZone:(nullable NSZone *)zone
{
return _instance;
}
- (id)copy
{
return _instance;
}
-(id)mutableCopy
{
return _instance;
}
@end
instancetype 和 id
id我们经常使用,当做一个类型不确定的OC对象,instancetype在一些系统的API里也经常看到,也是当做一个类型不确定的OC对象,那么它和id有什么区别呢?
比如刚才我们ARC单例的类方法,新增一个返回id类型的类方法:
//给外部提供的类方法
+ (instancetype)shareInstance;
//用于区别instancetype的测试方法
+ (id)makeInstance;
//实例方法
- (void)test;
实现:
//用于区别instancetype的测试方法
+ (id)makeInstance
{
return [[[self class] alloc] init];
}
- (void)test
{
}
实例化并调用,此时就会收到警告:
因为shareInstance返回的类型是instancetype,在编译期会进行类型检测,检测到它是ARCSingleton对象,所以识别到test方法;而makeInstance返回的是id类型,不检测对象类型,所以不知道它响应test方法。
网友评论