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. [UWP]抄抄《CSS 故障艺术》的动画

    1. 前言 什么是故障艺术(Glitch Art 风)?我们熟知的抖音的 LOGO 正是故障艺术其中一种表现形式.它有一种魔幻的感觉,看起来具有闪烁.震动的效果,很吸引人眼球.故障艺术它模拟了画面信号 ...

  2. cmdb简介

    目录: 1.为啥要做cmdb

  3. shell脚本的函数介绍和使用案例

    #前言:今天我们来聊聊shell脚本中的函数知识,看一下函数的优势,执行过程和相关的使用案例,我们也来看一下shell和python的函数书写方式有什么不同 #简介 .函数也具有别名类似的功能 .函数 ...

  4. 自定义上下文菜单,contextmenu事件

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. 阅读了这三篇文章,你也就基本理解了ASP.NET Core MVC框架的工作原理

    <200行代码,7个对象--让你了解ASP.NET Core框架的本质>让很多读者对ASP.NET Core管道有深刻的理解,知道了ASP.NET Core框架针对每个请求的处理流程.在过 ...

  6. OpenCV-Python ORB(面向快速和旋转的BRIEF) | 四十三

    目标 在本章中,我们将了解ORB的基础知识 理论 作为OpenCV的狂热者,关于ORB的最重要的事情是它来自" OpenCV Labs".该算法由Ethan Rublee,Vinc ...

  7. OpenCV-Python 理解特征 | 三十六

    目标 在本章中,我们将尝试理解什么是特征,为什么拐角重要等等 解释 你们大多数人都会玩拼图游戏.你会得到很多小图像,需要正确组装它们以形成大的真实图像.问题是,你怎么做?将相同的理论投影到计算机程序上 ...

  8. 分布式配置中心Apollo

    1,什么是分布式配置中心 项目中配置文件比较繁杂,而且不同环境的不同配置修改相对频繁,每次发布都需要对应修改配置,如果配置出现错误,需要重新打包发布,时间成本较高,因此需要做统一的分布式注册中心,能做 ...

  9. [React]核心概念

    本文是对React文档:核心概念部分的笔记,内容大致与文档相同. 文档链接 React哲学部分写的很好,务必要看 JSX JSX是JS的语法扩展,配合react使用,为JS和HTML的混写 JSX支持 ...

  10. Ubuntu文件(文件夹)创建(删除)

    创建 创建文件: touch a.txt创建文件夹: mkdir NewFolderName 删除 删除文件: rm a.txt删除文件夹: rmdir FolderName删除带有文件的文件夹: r ...