iOS多线程技术—单例模式(ARC)与(MRC)

iOS多线程技术—单例模式(ARC)

一、简单说明:

设计模式:多年软件开发,总结出来的一套经验、方法和工具

java中有23种设计模式,在ios中最常用的是单例模式和代理模式。

二、单例模式说明

(1)单例模式的作用 :可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问,从而方便地控制了实例个数,并节约系统资源。

(2)单例模式的使用场合:在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次),应该让这个类创建出来的对象永远只有一个。

(3)单例模式在ARC\MRC环境下的写法有所不同,需要编写2套不同的代码

可以用宏判断是否为ARC环境

#if __has_feature(objc_arc)
 // ARC
#else
// MRC
#endif

(4)在ARC中,单例模式的实现思路

在.m中保留一个全局的static的实例   static id _instance;

1)重写allocWithZone:方法,在这里创建唯一的实例(注意线程安全)

+ (id)allocWithZone:(struct _NSZone *)zone
{    @synchronized(self) {
        if (!_instance) {
            _instance = [super allocWithZone:zone];
        }
    }
    return _instance;
}

2)提供1个类方法让外界访问唯一的实例

+ (instancetype)sharedSoundTool
{
    @synchronized(self) {
        if (!_instance) {
            _instance = [[self alloc] init];
        }
    }
    return _instance;
}

3)实现copyWithZone:方法

+ (id)copyWithZone:(struct _NSZone *)zone
 {
     return _instance;
 }

(5)非ARC中(MRC),单例模式的实现(比ARC多了几个步骤)

实现内存管理方法

- (id)retain { return self; }

- (NSUInteger)retainCount { return 1; }

- (oneway void)release {}

- (id)autorelease { return self; }

三、单例模式(ARC)

1.说明

重写allocWithzone:方法,控制内存分配。因为alloc内部会调用该方法,每次调用allocWithzone:方法,系统都会创建一块新的内存空间。

alloc方法中:永远只分配一次内存

init方法中:保证所有的MP3数据都只加载一次。

2.代码示例

创建一个音频工具类,继承子NSObject类。

在该类中实现以下代码,观察:

 1 //
 2 //  YYAudioTool.m
 3 //  06-单例模式1
 4 //
 5 //  Created by apple on 14-6-25.
 6 //  Copyright (c) 2014年 itcase. All rights reserved.
 7 //
 8
 9 #import "YYAudioTool.h"
10 @interface YYAudioTool ()
11 //用来保存mp3文件
12 @property(nonatomic,strong)NSMutableDictionary *muscis;
13 @end
14 @implementation YYAudioTool
15 //构造方法
16 -(id)init
17 {
18     if (self=[super init]) {
19         //加载所需的音乐资源
20         //....
21 //        self.muscis=[NSMutableDictionary dictionary];
22 //        self.muscis[@"1.mp3"]=1mp3数据;
23 //        self.muscis[@"2.mp3"]=2mp3数据;
24     }
25     return self;
26 }
27
28 //两个方法的调用
29 +(id)alloc
30 {
31     NSLog(@"alloc----");
32     return [super alloc];
33 }
34
35 //控制内存分配,每次调用allocWithzone:方法,系统都会创建一块新的内存空间
36 +(id)allocWithZone:(struct _NSZone *)zone
37 {
38     NSLog(@"allocWithZone---");
39     return [super allocWithZone:zone];
40 }
41
42
43
44 @end

在主控制器中,创建工具类对象:

打印结果:

说明:在alloc内部会调用更底层的方法allocWithZone方法分配内存空间,上面的代码创建了四个不同的对象。

3.单例模式:设计思路

(1)永远只分配一块内存来创建对象

(2)提供一个类方法,返回内部唯一的一个变量

(3)最好保证init方法也只初始化一次

代码示例:

创建一个音频工具类,继承子NSObject类。

在该类中按照设计思路实现以下代码:

YYAudioTool.m文件

 1 //
 2 //  YYAudioTool.m
 3 //  06-单例模式1
 4 //
 5 //  Created by apple on 14-6-25.
 6 //  Copyright (c) 2014年 itcase. All rights reserved.
 7 //
 8
 9 #import "YYAudioTool.h"
10 @interface YYAudioTool ()
11 //用来保存mp3文件
12 @property(nonatomic,strong)NSMutableDictionary *muscis;
13 @end
14
15 @implementation YYAudioTool
16 //定义一份变量(整个程序运行过程中,只有一份)
17 static id _instace;
18 //单例模式:设计
19 //(1)永远只分配一块内存来创建对象
20 //(2)提供一个类方法,返回内部唯一的一个变量
21 //(3)最好保证init方法也只初始化一次
22
23 //构造方法
24 -(id)init
25 {
26 //    __block id obj=nil;
27     static id obj=nil;
28     static dispatch_once_t onceToken;
29     dispatch_once(&onceToken, ^{
30         if ((obj=[super init]) != nil) {
31             //加载所需的音乐资源
32             //....
33             //        self.muscis=[NSMutableDictionary dictionary];
34             //        self.muscis[@"1.mp3"]=1mp3数据;
35             //        self.muscis[@"2.mp3"]=2mp3数据;
36         }
37     });
38     self=obj;
39
40     return self;
41 }
42
43
44 //重写该方法,控制内存的分配,永远只分配一次存储空间
45 +(id)allocWithZone:(struct _NSZone *)zone
46 {
47
48     //里面的代码只会执行一次
49     static dispatch_once_t onceToken;
50     dispatch_once(&onceToken, ^{
51         _instace=[super allocWithZone:zone];
52     });
53     return _instace;
54 }
55
56 //类方法
57 +(id)sharedAudioTool
58 {
59   //里面的代码永远都只执行一次
60     static dispatch_once_t onceToken;
61     dispatch_once(&onceToken, ^{
62         _instace=[[self alloc]init];
63     });
64     return _instace;
65 }
66
67 +(id)copyWithZone:(struct _NSZone *)zone
68 {
69     return _instace;
70 }
71 @end

YYAudioTool.h文件

1 #import <Foundation/Foundation.h>
2
3 @interface YYAudioTool : NSObject
4 //提供一个类方法,返回内部唯一的一个变量
5 +(id)sharedAudioTool;
6 @end

主控制器中创建对象:

 1 //
 2 //  YYViewController.m
 3 //  06-单例模式1
 4 //
 5 //  Created by apple on 14-6-25.
 6 //  Copyright (c) 2014年 itcase. All rights reserved.
 7 //
 8
 9 #import "YYViewController.h"
10 #import "YYAudioTool.h"
11
12 @interface YYViewController ()
13
14 @end
15
16 @implementation YYViewController
17
18 - (void)viewDidLoad
19 {
20     [super viewDidLoad];
21 //    YYAudioTool *tool1=[[YYAudioTool alloc]init];
22 //    YYAudioTool *tool2=[[YYAudioTool alloc]init];
23     YYAudioTool *tool1=[YYAudioTool sharedAudioTool];
24     YYAudioTool *tool2=[YYAudioTool sharedAudioTool];
25     YYAudioTool *tool3=[[YYAudioTool alloc]init];
26     YYAudioTool *tool4=[[YYAudioTool alloc]init];
27     NSLog(@"%p--%p--%p--%p",tool1,tool2,tool3,tool4);
28 }
29
30 @end

观察打印结果:

说明:整个程序中只创建一个对象实例。

4.static补充:

注意:static id instace=nil;和static id instace;instace=nil;的区别

 

 四、非ARC模式下的单例模式

1.说明:把一个项目修改为非ARC的

2.MAC下单例模式代码示例:

新建一个工具类,让该类继承自NSObject。

YYAudioTool.m文件

 1 //
 2 //  YYAudioTool.m
 3 //  06-单例模式1
 4 //
 5 //  Created by apple on 14-6-25.
 6 //  Copyright (c) 2014年 itcase. All rights reserved.
 7 //
 8
 9 #import "YYAudioTool.h"
10 @interface YYAudioTool ()
11 //用来保存mp3文件
12 @property(nonatomic,strong)NSMutableDictionary *muscis;
13 @end
14
15 @implementation YYAudioTool
16 //定义一份变量(整个程序运行过程中,只有一份)
17 static id _instace;
18 //单例模式:设计
19 //(1)永远只分配一块内存来创建对象
20 //(2)提供一个类方法,返回内部唯一的一个变量
21 //(3)最好保证init方法也只初始化一次
22
23 //构造方法
24 -(id)init
25 {
26 //    __block id obj=nil;
27     static id obj=nil;
28     static dispatch_once_t onceToken;
29     dispatch_once(&onceToken, ^{
30         if ((obj=[super init]) != nil) {
31
32         }
33     });
34     self=obj;
35
36     return self;
37 }
38
39
40 //重写该方法,控制内存的分配,永远只分配一次存储空间
41 +(id)allocWithZone:(struct _NSZone *)zone
42 {
43
44     //里面的代码只会执行一次
45     static dispatch_once_t onceToken;
46     dispatch_once(&onceToken, ^{
47         _instace=[super allocWithZone:zone];
48     });
49     return _instace;
50 }
51
52 //类方法
53 +(id)sharedAudioTool
54 {
55   //里面的代码永远都只执行一次
56     static dispatch_once_t onceToken;
57     dispatch_once(&onceToken, ^{
58         _instace=[[self alloc]init];
59     });
60     return _instace;
61 }
62
63 //重写release方法
64 //oneway :分布式对象
65 -(oneway void)release
66 {
67 }
68
69 //不管调用哪个方法,返回的都是唯一的实例,所以这里self和instace是一样的
70 -(id)autorelease
71 {
72     return self;
73 }
74
75 -(id)retain
76 {
77     return self;
78 }
79
80 -(NSUInteger)retainCount
81 {
82     return 1;
83 }
84
85 +(id)copyWithZone:(struct _NSZone *)zone
86 {
87     return _instace;
88 }
89 @end

YYAudioTool.h文件

 1 //
 2 //  YYAudioTool.h
 3 //  06-单例模式1
 4 //
 5 //  Created by apple on 14-6-25.
 6 //  Copyright (c) 2014年 itcase. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10
11 @interface YYAudioTool : NSObject
12 //提供一个类方法,返回内部唯一的一个变量
13 +(id)sharedAudioTool;
14 @end

主控制器中创建对象:

 1 //
 2 //  YYViewController.m
 3 //  06-单例模式1
 4 //
 5 //  Created by apple on 14-6-25.
 6 //  Copyright (c) 2014年 itcase. All rights reserved.
 7 //
 8
 9 #import "YYViewController.h"
10 #import "YYAudioTool.h"
11
12 @interface YYViewController ()
13
14 @end
15
16 @implementation YYViewController
17
18 - (void)viewDidLoad
19 {
20     [super viewDidLoad];
21     YYAudioTool *tool1=[YYAudioTool sharedAudioTool];
22     YYAudioTool *tool2=[YYAudioTool sharedAudioTool];
23     YYAudioTool *tool3=[YYAudioTool sharedAudioTool];
24     YYAudioTool *tool4=[[YYAudioTool alloc]init];
25
26     NSLog(@"%p--%p--%p--%p",tool1,tool2,tool3,tool4);
27
28     //对象创建只会,release对象会销毁,无法再创建新的对象(因为单例),所以还需要重写release方法
29     [tool1 release];
30     [tool2 release];
31     [tool3 release];
32     [tool4 release];
33 }
34
35 @end

打印结果:

说明:整个程序过程中,只创建一个对象实例。

 五、把单例代码定义为一个带参数的宏

1.新的困扰

弊端:如果又创建一个新的类,是否又要把文件代码拷贝一份,所以这里可以考虑把固定的代码写成宏。

由于项目中代码经常有移植的需要,要求项目中又有ARC的,又有非ARC的,应该怎么应用单例模式?

不管项目是ARC的还是非ARC的,这个宏都有用。可以先判断编译器的环境,判断当前环境是否是ARC的。

条件编译的使用:

2.使用条件编译,并把单例模式的代码定义为宏。

新建一个.h头文件

  把代码定义为宏,头文件中的代码如下:

 1 // ## : 连接字符串和参数
 2 #define singleton_h(name) + (instancetype)shared##name;
 3
 4 #if __has_feature(obj_arc)  //如果是ARC
 5 #define singleton_m(name)  6 static id _instance;  7 + (id)allocWithZone:(struct _NSZone *)zone  8 {  9     static dispatch_once_t onceToken; 10     dispatch_once(&onceToken, ^{ 11         _instance = [super allocWithZone:zone]; 12     }); 13     return _instance; 14 } 15 16 + (instancetype)shared##name 17 { 18     static dispatch_once_t onceToken; 19     dispatch_once(&onceToken, ^{ 20         _instance = [[self alloc] init]; 21     }); 22     return _instance; 23 } 24 25 + (id)copyWithZone:(struct _NSZone *)zone 26 { 27     return _instance; 28 }
29
30 #else //非ARC
31 #define singleton_m(name) 32 static id _instance; 33 + (id)allocWithZone:(struct _NSZone *)zone 34 { 35     static dispatch_once_t onceToken; 36     dispatch_once(&onceToken, ^{ 37         _instance = [super allocWithZone:zone]; 38     }); 39     return _instance; 40 } 41  42 + (instancetype)shared##name 43 { 44     static dispatch_once_t onceToken; 45     dispatch_once(&onceToken, ^{ 46         _instance = [[self alloc] init]; 47     }); 48     return _instance; 49 } 50  51 - (oneway void)release 52 { 53  54 } 55  56 - (id)autorelease 57 { 58     return _instance; 59 } 60  61 - (id)retain 62 { 63     return _instance; 64 } 65  66 - (NSUInteger)retainCount 67 { 68     return 1; 69 } 70  71 + (id)copyWithZone:(struct _NSZone *)zone 72 { 73     return _instance; 74 }
75 #endif

在程序中的应用:

控制器问价代码如下:

 1 #import "YYViewController.h"
 2 #import "YYAudioTool.h"
 3
 4 @interface YYViewController ()
 5
 6 @end
 7
 8 @implementation YYViewController
 9
10 - (void)viewDidLoad
11 {
12     [super viewDidLoad];
13     YYAudioTool *tool1=[YYAudioTool sharedAudioTool];
14
15     //对象创建后,需要考虑
16 //    (1)alloc init
17 //    (2)release
18 //    (3)copy copy内部会调用另外一个方法copywithzone
19 //    (4)autorelease
20 //
21     YYAudioTool *tool2=[YYAudioTool sharedAudioTool];
22     YYAudioTool *tool3=[YYAudioTool sharedAudioTool];
23     NSLog(@"%p---%p---%p",tool1,tool2,tool3);
24     [tool2 release];
25     [tool3 release];
26     [tool1 release];
27
28 }
29
30 @end

工具类的头文件代码如下:

 1 #import "YYViewController.h"
 2 #import "YYAudioTool.h"
 3
 4 @interface YYViewController ()
 5
 6 @end
 7
 8 @implementation YYViewController
 9
10 - (void)viewDidLoad
11 {
12     [super viewDidLoad];
13     YYAudioTool *tool1=[YYAudioTool sharedAudioTool];
14
15     //对象创建后,需要考虑
16 //    (1)alloc init
17 //    (2)release
18 //    (3)copy copy内部会调用另外一个方法copywithzone
19 //    (4)autorelease
20 //
21     YYAudioTool *tool2=[YYAudioTool sharedAudioTool];
22     YYAudioTool *tool3=[YYAudioTool sharedAudioTool];
23     NSLog(@"%p---%p---%p",tool1,tool2,tool3);
24     [tool2 release];
25     [tool3 release];
26     [tool1 release];
27
28 }
29
30 @end

工具类的实现部分代码如下:

 1 //
 2 //  YYAudioTool.h
 3 //  06-单例模式1
 4 //
 5 //  Created by apple on 14-6-25.
 6 //  Copyright (c) 2014年 itcase. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10 #import "Singleton.h"
11
12 @interface YYAudioTool : NSObject
13 ////提供一个类方法,返回内部唯一的一个变量
14 //+(id)sharedAudioTool;
15 singleton_h(AudioTool)
16 @end

补充说明:如果把代码下载dispatch_once里面,那么它内部默认会进行加锁。

六、补充

问题:ARC和非ARC单例模式的区别?

由于非ARC是进行手动内存管理,所以需要注意下面一个方法,在项目中通常使用宏。

- (id)retain { return self; }

- (NSUInteger)retainCount { return 1; }

- (oneway void)release {}

- (id)autorelease { return self; }

时间: 2024-10-14 12:51:17

iOS多线程技术—单例模式(ARC)与(MRC)的相关文章

iOS多线程技术—GCD介绍

iOS多线程技术—GCD介绍 一.简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 GCD是苹果公司为多核的并行运算提出的解决方案 GCD会自动利用更多的CPU内核(比如双核.四核) GCD会自动管理线程的生命周期(创建线程.调度任务.销毁线程) 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码 3.提示 (1)GCD存在于libdispatch.dylib这个库中,

iOS 多线程技术2

iOS 多线程技术2 NSOperation NSInvocationOperation //创建一个队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //创建子任务,定义子任务必须是 NSOperation 的子类 NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(dosome

OA01-一个Demo展示iOS多线程技术的基本应用场景

最近在看iOS关于GCD.NSOperation多线程编程技术编程指南的时候写了个 小Demo,以7个小场景基本涵盖多线程技术的主流用法:其实多线程技术早在大学 读书的时候,基本思路就已经清晰了,不同操作系统的多线程实现也大同小异,iOS 平台下原理也是一样,关键就在与,能否熟练的.很顺畅的根据应用场景来选用相应 的多线程技术.阅读苹果官方文档和一些别人写的博客的时候也依然有种隔靴捞痒的 感觉:书读百边,不如实践一遍啊,SO,尽管网上相关的博客一大堆(首推这篇: http://www.cocoa

iOS多线程技术—线程的状态

iOS多线程技术—线程的状态 一.简单介绍 线程的创建: self.thread=[[NSThread alloc]initWithTarget:self selector:@selector(test) object:nil]; 说明:创建线程有多种方式,这里不做过多的介绍. 线程的开启: [self.thread start]; 线程的运行和阻塞: (1)设置线程阻塞1,阻塞2秒 [NSThread sleepForTimeInterval:2.0]; (2)第二种设置线程阻塞2,以当前时间

iOS多线程技术—自定义NSOperation

iOS多线程技术—自定义NSOperation 一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UITableViewController. // // YYViewController.h // 01-自定义Operation // // Created by apple on 14-6-26. // Copyright (c) 2014年 itcase. All rights reserved.

iOS多线程技术—GCD的用法

iOS多线程技术—GCD的用法 一.主队列介绍 主队列:是和主线程相关联的队列,主队列是GCD自带的一种特殊的串行队列,放在主队列中得任务,都会放到主线程中执行. 提示:如果把任务放到主队列中进行处理,那么不论处理函数是异步的还是同步的都不会开启新的线程. 获取主队列的方式: 1 // 2 // YYViewController.m 3 // 12-GCD的基本使用(主队列) 4 // 5 // Created by 孔医己 on 14-6-25. 6 // Copyright (c) 2014

iOS 多线程技术1

iOS 多线程技术1 iOS 有三种多线程编程技术: NSThread NSOperation GCD 它们的抽象程度由低到高,越高的使用起来越简单. NSThread 显示调用 NSthread 类 类方法 + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument; 实例方法 - (instancetype)initWithTarget:(id)target selecto

iOS多线程技术—NSOperation用法

iOS多线程技术—NSOperation用法 一.NSOperation简介 1.简单说明 NSOperation的作?:配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperationQueue实现多线程的具体步骤: (1)先将需要执行的操作封装到一个NSOperation对象中 (2)然后将NSOperation对象添加到NSOperationQueue中 (3)系统会?动将NSOperationQueue中的NSOperat

iOS多线程技术—多线程简单介绍

iOS多线程技术—多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcode,系统就会分别启动2个进程 通过“活动监视器”可以查看Mac系统中所开启的进程 2.什么是线程 1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程) 线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行 比如使用酷狗播放音乐.使用迅雷下载电影,都需要在线程中执行 3.线程的