说到单例和多线程我们先来看看这两个的概念
一.多线程
说起多线程不得不说一线什么是线程,说到线程,脑海里有浮出一个概念,那就是进程
1.什么是进程
进程官方概念是资源分配的基本单位,按照我自己的理解,简单来说就是计算机运行一个程序就是一个进程,因为这是一个比较抽象的概念,每个人的理解都不一样,但是意思却是那么个意思
2.什么是线程
线程是CPU独立运行和独立调度的基本单位,每个进程至少有一个线程,是进程的执行路径
3.多线程
多线程是指一个进程同时执行多条路径
4.iOS中多线程通常使用NSThread、NSOperation和GCD
a、NSThread的几种开线程方式
*先创建,后启动
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[thread start];
*直接启动[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
[self performSelectorInBackground:@selector(run) withObject:nil];
*其他方式
NSThread *current = [NSThread currentThread];
+ (NSThread *)mainThread; // 获得主线程
*线程间的通信performSelectorOnMainThread.....
b、GCD队列类型
*并发队列
获得全局的并发队列: dispatch_get_global_queue
*串行队列
dispatch_queue_create
*主队列
dispatch_get_main_queue
*线程间的通信
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行耗时的异步操作...
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程,执行UI刷新操作
});
});
*其他用法
dispatch_once
dispatch_after
dispatch_group_async\dispatch_group_notify
c、NSOperation和NSOperationQueue
*基本使用创建其子类
NSInvocationOperation
NSBlockOperation
*最大并发数量的设置
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
*设置一依赖
[operationB addDependency:operationA]; // 操作B依赖于操作A
二、单例
1.什么是单例
永远只分配一块内存来创建对象
提供一个类方法,返回内部唯一的一个实例
最好保证init方法也只初始化一次
2.单例模式的使用场合
如果在整个应用程序中,共享一份资源,这个资源只需要创建初始化一次
3.单例的应用
我们说了,单例的使用是整个应用程序中共享一份资源,这个资源只需要创建初始化一次,所以我们保证共享资源的这个类(继承NSObject)创建出来的对象只有一个
先来看一下一般单例在ARC中的写法,我们再来说一下为什么要这么写
#import "Tools.h"
@implementation Tools
// 创建静态对象 防止外部访问
static Tools *_instance;
- (id)init
{
if (self = [super init]) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 加载资源
});
}
return self;
}
+(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;
}
为什么要这么写呢,解释一下,一般我们在创建一个对象的时候,通常都要初始化这个对象,例如我在使用Tool这个共享类的时候我需要初始化一下
Tool *tool1 = [[Tool alloc] init];
那么,我每次调alloc,就需要给这个对象分配一个内存空间,造成资源的浪费,感兴趣的可以打印tool的地址试一下,所以我们需要重写+(instancetype)allocWithZone:(struct _NSZone *)zone
现在,再来看一下,我们每次调alloc返回的都是同一个对象,那么我们使用类方法是不是比较方便呢,所以使用
+(instancetype)shareTool
{
//return _instance;
// 最好用self 用Tools他的子类调用时会出现错误
return [[self alloc]init];
}
这里还有另一种完整的写法,这里每次alloc还是没次会调[super init]这个方法
+ (instancetype)sharedTools
{
// 里面的代码永远只执行1次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
// 返回对象
return _instance;
}
MRC中单例代码实现
配置好MRC环境之后,在ARC代码基础上重写下面的三个方法即可
-(oneway void)release
{
}
-(instancetype)retain
{
return _instance;
}
-(NSUInteger)retainCount
{
return MAXFLOAT;
}
三、单例的高级写法
如果想要一劳永逸,我们将面临两个问题1:如何写一份单例代码在ARC和MRC环境下都适用?
2:如何使一份单例代码可以多个类共同使用
为了解决这两个问题,我们可以在 PCH文件使用代参数的宏和条件编译
利用条件编译来判断是ARC还是MRC环境
创建一个名叫Singleton的PCH文件
// ## : 连接字符串和参数
#define singleton_h(name) + (instancetype)shared##name;//传入的单例名叫什么,因为所有单例写法是一样的,只是名字不同而已
#if __has_feature(objc_arc) // 判断是否是ARC
#define singleton_m(name) \
static id _instance; \
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [super allocWithZone:zone]; \
}); \
return _instance; \
} \
\
+ (instancetype)shared##name \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [[self alloc] init]; \
})\
return _instance; \
} \
+ (id)copyWithZone:(struct _NSZone *)zone \
{ \
return _instance; \
}
#else // 非ARC
#define singleton_m(name) \
static id _instance; \
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [super allocWithZone:zone]; \
}); \
return _instance; \
} \
\
+ (instancetype)shared##name \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [[self alloc] init]; \
}); \
return _instance; \
} \
\
- (oneway void)release \
{ \
\
} \
\
- (id)autorelease \
{ \
return _instance; \
} \
\
- (id)retain \
{ \
return _instance; \
} \
\
- (NSUInteger)retainCount \
{ \
return 1; \
} \
\
+ (id)copyWithZone:(struct _NSZone *)zone \
{ \
return _instance; \
}
#endif
在每个单例里面的使用,导入头文件HMAudioTool.h
#import <Foundation/Foundation.h>
#import "Singleton.h"
@interface HMAudioTool : NSObject
singleton_h(AudioTool)
@end
HMAudioTool.m
#import "HMAudioTool.h"
@interface HMAudioTool()
@end
@implementation HMAudioTool
定义一份变量(整个程序运行过程中, 只有1份)
//static id _instance;
- (id)init
{
if (self = [super init]) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 加载资源
});
}
return self;
}
singleton_m(AudioTool)