iOS单例模式以及多线程使用深入详解

说到单例和多线程我们先来看看这两个的概念

一.多线程

说起多线程不得不说一线什么是线程,说到线程,脑海里有浮出一个概念,那就是进程

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)



猜你喜欢

转载自blog.csdn.net/qq_33298465/article/details/80605619
今日推荐