AJ分享,必须精品

单例模式

1:单例模式的作用

可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问
从而方便地控制了实例个数,并节约系统资源

单例模式的使用场合
在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次)

简单来说,就是我弄了一个工具类,他就有一份,比如我设计了一个音乐播放器NYPlayer,这个播放器类我就想他有一个,这就是单例,我用的时候我只需要让播放器干活,如果多个的话我不知道指定那个,或者有重复会出bug。
百度百科是这样说的:单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
简单来说,就是让一个类的事物里面只有一个对象。

2:ARC中,单例模式的实现

过程:
在.m中保留一个全局的static的实例
这里要用static,记住他,稍后我回写一个关于static关键词的博客。

static id _instance;

重写allocWithZone:方法,在这里创建唯一的实例(注意线程安全)
创建类的时候调用[类名 alloc]方法的时候,内部会自动调用allcWithZone方法,加载一个空间,所以我们只要重写这个方法,当我们定义的全局变量instance有值得时候,就会直接返回,如果没有,就会调用父类方法[super allocWithZone:zone]并赋值给instance,但是这时候有一个危险,那就是如果这里有两个线程都进来了,那样就会分配两次,所以我们要给本段程序加锁。

+ (id)allocWithZone:(struct _NSZone *)zone {
if (_instance == nil) { // 防止频繁加锁
@synchronized(self) {
if (_instance == nil) { // 防止创建多次
_instance = [super allocWithZone:zone];
}
}
}
return _instance;
}

提供一个类方法让外界访问唯一的实例。
跟上面的allocWithzone一样,不过有所不同的是这里调用的时【[self alloc] init】方法。

+ (instancetype)sharedMusicTool {
if (_instance == nil) { // 防止频繁加锁
@synchronized(self) {
if (_instance == nil) { // 防止创建多次
_instance = [[self alloc] init];
}
}
}
return _instance;
} 实现copyWithZone:方法
- (id)copyWithZone:(struct _NSZone *)zone {
return _instance;
}

3:MRC中的单例模式

过程:
非ARC中(MRC),单例模式的实现(比ARC多了几个步骤)
实现内存管理方法。

- (id)retain { return self; }//父类里面是计数器+1,重写将不会+1
- (NSUInteger)retainCount { return 1; }//父类里面返回当前对象的计数个数
- (oneway void)release {}//父类里面是计数器-1,重写将不会-1
- (id)autorelease { return self; }//父类里面内存自动管理释放的,跟内存池有关

GCD下完美单例模式(ARC&MRC通吃)

判断ARC的宏

这里首先要知道一个宏了 __has_feature(objc_arc)

单例模式在ARC\MRC环境下的写法有所不同,需要编写2套不同的代码
可以用宏判断是否为ARC环境。

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

传值的宏

就一句

#define NYSingletonH(name) + (instancetype)shared##name;

用的时候传进name,他就会自动替换了。

用GDC运行一次代码解决

怎么解决呢 ?其实就是把加锁换成GCD的一次性代码

代码如下:

+(id)allocWithZone:(struct _NSZone *)zone
{
if (_instance == nil) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (_instance == nil) {
_instance = [super allocWithZone:zone];
}
});
}
return _instance;
}

快捷方式,xcode中只要敲dispatch_once就自动有啦,填填写写。

终极方式,以后单例不用敲代码了,直接掉就行了。

第一步,简历一个.h文件,例如

第二步,文件中写入以下代码:

// .h文件
#define NYSingletonH(name) + (instancetype)shared##name; // .m文件
#define NYSingletonM #if __has_feature(objc_arc)
#define NYSingletonM(name)\
static id _instance;\
\
+(id)allocWithZone:(struct _NSZone *)zone\
{\
if (_instance == nil) {\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
if (_instance == nil) {\
_instance = [super allocWithZone:zone];\
}\
});\
}\
return _instance;\
}\
\
+(instancetype)shared##name\
{\
if (_instance == nil) {\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
if (_instance == nil) {\
_instance = [[self alloc]init];\
}\
});\
}\
return _instance;\
}\
\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instance;\\
} #else
#define NYSingletonM(name)\
static id _instance;\
\
+(id)allocWithZone:(struct _NSZone *)zone\
{\
if (_instance == nil) {\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
if (_instance == nil) {\
_instance = [super allocWithZone:zone];\
}\
});\
}\
return _instance;\
}\
\
+(instancetype)shared##name\
{\
if (_instance == nil) {\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
if (_instance == nil) {\
_instance = [[self alloc]init];\
}\
});\
}\
return _instance;\
}\
\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
\
-(id)retain\
{\
return self;\
}\
-(NSUInteger)retainCount{return 1;}\
-(oneway void)release{}\
-(id)autorelease{return self;} #endif

\符号是让后面的东东包含到上一行去,因为define只能定义一行。

第三步:在pch文件中写入调用代码:

#import "NYSingleton.h"

第四步:在需要用到的类中调用:

在点h文件中调用这个

在点m文件中调用这个

最后调用,还是单例:

补充,自定义宏代替NSLog

注意:开发过程中,会使用NSLog来打印信息用于调试,但releae的软件却不能包含NSLog,可能会有被打回的风险,但是要是全部注释掉NSLog那太痛苦了,也不利于以后的调试。

下面,我们可以采用自定义宏来取代NSLog,只在我们想要的时候输出


/*
XCode LLVM XXX - Preprocessing中Debug会添加 DEBUG=1 标志
*/
#ifdef DEBUG
#define NSLog(FORMAT, ...) fprintf(stderr,"%s:%d\t%s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#else
#define NSLog(FORMAT, ...) nil
#endif

把以上代码粘贴到ProjectName-Prefix.pch文件中。

在调试的时候,会输出(格式:文件名:行号)日志。

在Release正式版本的时候,会关闭日志输出。

因为XCode LLVM XXX - Preprocessing中Debug会添加 DEBUG=1 标志。当然我们也能把DEBUG直接换成数字1来设置。

AJ学IOS(52)多线程网络之GCD下单例设计模式的更多相关文章

  1. AJ学IOS(48)多线程网络之多线程简单了解

    AJ分享,必须精品 一:进程和线程 1:什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内. 比如同时打开QQ.Xcode,系统就会分 ...

  2. iOS开发多线程篇 08 —GCD的常见用法

    iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...

  3. iOS开发多线程篇 07 —GCD的基本使用

    iOS开发多线程篇—GCD的基本使用 一.主队列介绍 主队列:是和主线程相关联的队列,主队列是GCD自带的一种特殊的串行队列,放在主队列中得任务,都会放到主线程中执行. 提示:如果把任务放到主队列中进 ...

  4. iOS开发多线程篇 05 —GCD介绍

    iOS开发多线程篇—GCD介绍 一.简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 G ...

  5. AJ学IOS 之微博项目实战(2)微博主框架-自定义导航控制器NavigationController

    AJ分享,必须精品 一:添加导航控制器 上一篇博客完成了对底部的TabBar的设置,这一章我们完成自定义导航控制器(NYNavigationController). 为啥要做自定义呢,因为为了更好地封 ...

  6. AJ学IOS(13)UI之UITableView学习(下)汽车名牌带右侧索引

    AJ分享,必须精品 先看效果图 代码 ViewController #import "NYViewController.h" #import "NYCarGroup.h& ...

  7. AJ学IOS(50)多线程网络之GCD简单介绍(任务,队列)

    AJ分享,必须精品 GCD简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 GCD是苹果 ...

  8. AJ学IOS(51)多线程网络之GCD下载合并图片_队列组的使用

    AJ分享,必须精品 合并图片(图片水印)第一种方法 效果 实现: 思路: 1.分别下载2张图片:大图片.LOGO 2.合并2张图片 3.显示到一个imageView身上 // 异步下载 dispatc ...

  9. AJ学IOS(49)多线程网络之线程的创建NSThreand

    AJ分享,必须精品 一:NSThread的基本使用 1:创建和启动线程 一个NSThread对象就代表一条线程 创建.启动线程 NSThread *thread = [[NSThread alloc] ...

随机推荐

  1. leetcode面试题 17.16. 按摩师

    leetcode面试题 17.16. 按摩师 又一道动态规划题目 动态规划的核心就是总结出一个通行的方程. 但是这道题似乎不太适合使用递归的方式. 所以使用for循环遍历数组. class Solut ...

  2. 108. Convert Sorted Array to Binary Search [Python]

    108. Convert Sorted Array to Binary Search Given an array where elements are sorted in ascending ord ...

  3. Recover刷机简介

    Recovery Recovery是一种可以对安卓手机内部的数据文件进行修改的模式,类似电脑的PE.不同的recovery有不同的功能.使用recovery可以说是刷机(卡刷)的基础,想要比较顺畅的刷 ...

  4. drf 简介以及部分源码分析

    目录 复习 drf框架 全称:django-rest framework 知识点 接口 restful接口规范 基于restful规范的原生Django接口 主路由:url.py api组件的子路由: ...

  5. MySQL数据库02

    MySQL数据库 前言: 前面我们了解了什么是数据库,什么是MySQL数据库以及如何运用,接下来我们接着深入学习MySQL. (提前声明,以下所提供的事例不标准,仅供参考) 数据库的备份与还原: 备份 ...

  6. 《面试经典系列》- MySQL数据库存储引擎

    一.MySQL有多少种存储引擎? 在MySQL5之后,支持的存储引擎有十多个,但是我们常用的就那么几种,而且,默认支持的也是 InnoDB. 通过命令:show engines \g,我们可以查看到当 ...

  7. Visual Studio2019+OpenCV3.4.9环境搭建

    让人头疼的vs2019+opencv环境配置 准备: visual studio2019: opencv 3.4.9: 耐心: 说明:vs2019属性管理器没有Microsoft.Cpp.x64.us ...

  8. ubuntu 18.04下virtualbox安装windows虚拟机+增强功能+secureCRT

    先强调一下,我是在Ubuntu里安装windows虚拟机,如果要看如何安装linux虚拟机的话,那么你走错地方了. 我一直使用Linux系统做开发的,选择Ubuntu是因为多数常用软件对Ubuntu支 ...

  9. 说说自己为什么用Mac不用Win系统?

    原本Mac和Win系统各有优劣,但偏偏最近有人误导身边的朋友说"学编程肯定是Windows系统呀,Mac不行的",又不给出有说服力的理由,于是我心有愤懑,正好趁机总结一下自己对于两 ...

  10. [leetcode] 位操作题解-2

    本文是 leetcode 位操作题库的题目解析.点击每个标题可进入题目页面. 重复的DNA序列 题目:所有 DNA 都由一系列缩写为 A,C,G 和 T 的核苷酸组成,例如:"ACGAATT ...