AJ学IOS(52)多线程网络之GCD下单例设计模式
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下单例设计模式的更多相关文章
- AJ学IOS(48)多线程网络之多线程简单了解
AJ分享,必须精品 一:进程和线程 1:什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内. 比如同时打开QQ.Xcode,系统就会分 ...
- iOS开发多线程篇 08 —GCD的常见用法
iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...
- iOS开发多线程篇 07 —GCD的基本使用
iOS开发多线程篇—GCD的基本使用 一.主队列介绍 主队列:是和主线程相关联的队列,主队列是GCD自带的一种特殊的串行队列,放在主队列中得任务,都会放到主线程中执行. 提示:如果把任务放到主队列中进 ...
- iOS开发多线程篇 05 —GCD介绍
iOS开发多线程篇—GCD介绍 一.简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 G ...
- AJ学IOS 之微博项目实战(2)微博主框架-自定义导航控制器NavigationController
AJ分享,必须精品 一:添加导航控制器 上一篇博客完成了对底部的TabBar的设置,这一章我们完成自定义导航控制器(NYNavigationController). 为啥要做自定义呢,因为为了更好地封 ...
- AJ学IOS(13)UI之UITableView学习(下)汽车名牌带右侧索引
AJ分享,必须精品 先看效果图 代码 ViewController #import "NYViewController.h" #import "NYCarGroup.h& ...
- AJ学IOS(50)多线程网络之GCD简单介绍(任务,队列)
AJ分享,必须精品 GCD简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 GCD是苹果 ...
- AJ学IOS(51)多线程网络之GCD下载合并图片_队列组的使用
AJ分享,必须精品 合并图片(图片水印)第一种方法 效果 实现: 思路: 1.分别下载2张图片:大图片.LOGO 2.合并2张图片 3.显示到一个imageView身上 // 异步下载 dispatc ...
- AJ学IOS(49)多线程网络之线程的创建NSThreand
AJ分享,必须精品 一:NSThread的基本使用 1:创建和启动线程 一个NSThread对象就代表一条线程 创建.启动线程 NSThread *thread = [[NSThread alloc] ...
随机推荐
- python通过scapy编写arp扫描器
多网卡的情况下发送二层包需要配置网卡 三层包不需要配置接口发包方法: sr() 发送三层数据包,等待接收一个或者多个数据包的响应 sr1() 发送三层数据包,只会接收一个数据包的响应 srp() 发送 ...
- 最详细的SSM(Spring+Spring MVC+MyBatis)项目搭建
速览 使用Spring+Spring MVC+MyBatis搭建项目 开发工具IDEA(Ecplise步骤类似,代码完全一样) 项目类型Maven工程 数据库MySQL8.0 数据库连接池:Druid ...
- JAVA正则-检验QQ是否合法
/* * 0不能开头,全数字,位数5-10位 * 123456 */ public static void checkQQ(){ String QQ = " 123456 "; / ...
- drf 权限认证
目录 复习 前期准备 三大认证简介 AbstracUser源码分析 自定义User下的权限六表 models.py 到settings.py中注册 注意点: 执行数据迁移的俩条命令 创建超级用户 t_ ...
- 动态规划-01背包-Tallest Billboard
2020-02-07 17:46:32 问题描述: 问题求解: 解法一:BF 看问题规模看似可以直接暴力解决. 如果直接去解肯定是会超时的,因为每次将原空间划分成A区域,B区域和剩余区域的时间复杂度为 ...
- 面试刷题17:线程两次start()会发生什么?
线程是并发编程的基础元素,是系统调度的最小单元,现代的jvm直接对应了内核线程.为了降低并发编程的门槛,go语言引入了协程. 你好,我是李福春,我在准备面试,今天的题目是? 一个线程两次调用start ...
- 斯坦福经典AI课程CS 221官方笔记来了!机器学习模型、贝叶斯网络等重点速查...
[导读]斯坦福大学的人工智能课程"CS 221"至今仍然是人工智能学习课程的经典之一.为了方便广大不能亲临现场听讲的同学,课程官方推出了课程笔记CheatSheet,涵盖4大类模型 ...
- 运行redis数据库
启动redis服务器:redis-server /usr/local/redis-5.0.5/etc/redis.conf 关闭: redis-cli shutdown启动客户端:进入bin文件夹,输 ...
- 将Windows项目发布到Ubuntu服务器详细教程(Windows编程,Ubuntu服务器做解释器)
前期准备 (1)专业版Pycharm(社区版没有deployment功能),学生,教师可申请免费专业版,详情可看我的博客. (2)可通过SSH连接Ubuntu服务器,并且服务器安装了Python解释器 ...
- 瀑布流vue-waterfall的高度设置
最近用vue做项目,用到了瀑布流vue-waterfall,其中遇到高度的设置问题,大概介绍下,希望可以帮到一些人 1.安装 npm install --save vue-waterfall 2.引入 ...