概念相关

  • 单例模式

    • 在程序运行过程,一个类只有一个实例
  • 使用场合
    • 在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次)

static


  • static关键字会在声明变量的时候分配内存,在程序运行期间只分配一次内存。之后再访问时,实际都是在访问原先分配的内存
  • 如果使用static来修饰局部变量,那么局部变量在代码块结束后将不会回收,下次使用保持上次使用后的值。
  • 如果使用static来修饰全局变量,那么表示该全局变量只在本文件中有效,外界无法使用extern来引用。static变量的作用域被限制在定义变量的当前文件中,其它文件是不能访问的。

ARC实现单例


步骤

01 在类的内部提供一个static修饰的全局变量
02 提供一个类方法,方便外界访问
03 重写+allocWithZone方法,保证永远都只为单例对象分配一次内存空间
04 严谨起见,重写-copyWithZone方法和-MutableCopyWithZone方法

源码


static ZCTools *_instance; + (instancetype)shareTools
{
return [[self alloc]init];
} + (instancetype)allocWithZone:(struct _NSZone *)zone
{
@synchronized(self) {
if (_instance == nil) {
_instance = [super allocWithZone:zone];
}
}
return _instance;
} - (nonnull id)copyWithZone:(nullable NSZone *)zone
{
return _instance;
} - (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone
{
return _instance;
}

代码分析

//提供一个static修饰的全局变量,强引用着已经实例化的单例对象实例
static ZCTools *_instance; //类方法,返回一个单例对象
+ (instancetype)shareTools
{
//注意:这里建议使用self,而不是直接使用类名Tools(考虑继承)
return [[self alloc]init];
} //保证永远只分配一次存储空间
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
//使用GCD中的一次性代码
// static dispatch_once_t onceToken;
// dispatch_once(&onceToken, ^{
// _instance = [super allocWithZone:zone];
// }); //使用加锁的方式,保证只分配一次存储空间
@synchronized(self) {
if (_instance == nil) {
_instance = [super allocWithZone:zone];
}
}
return _instance;
}
/*
1. mutableCopy 创建一个新的可变对象,并初始化为原对象的值,新对象的引用计数为 1;
2. copy 返回一个不可变对象。分两种情况:(1)若原对象是不可变对象,那么返回原对象,并将其引用计数加 1 ;(2)若原对象是可变对象,那么创建一个新的不可变对象,并初始化为原对象的值,新对象的引用计数为 1。
*/
//让代码更加的严谨
- (nonnull id)copyWithZone:(nullable NSZone *)zone
{
// return [[self class] allocWithZone:zone];
return _instance;
} - (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone
{
return _instance;
}

MRC实现单例


步骤

01 在类的内部提供一个static修饰的全局变量
02 提供一个类方法,方便外界访问
03 重写+allocWithZone方法,保证永远都只为单例对象分配一次内存空间
04 严谨起见,重写-copyWithZone方法和-MutableCopyWithZone方法
05 重写release方法
06 重写retain方法
07 建议在retainCount方法中返回一个最大值

配置MRC环境

01 注意ARC不是垃圾回收机制,是编译器特性
02 配置MRC环境:build setting ->搜索automatic ref->修改为NO

源码

static ZCTools *_instance;

+ (instancetype)shareTools
{
return [[self alloc]init];
} + (instancetype)allocWithZone:(struct _NSZone *)zone
{
@synchronized(self) {
if (_instance == nil) {
_instance = [super allocWithZone:zone];
}
}
return _instance;
} - (nonnull id)copyWithZone:(nullable NSZone *)zone
{
return _instance;
} - (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone
{
return _instance;
} - (oneway void)release
{
} - (instancetype)retain
{
return _instance;
} - (NSUInteger)retainCount
{
return MAXFLOAT;
}

代码分析

//提供一个static修饰的全局变量,强引用着已经实例化的单例对象实例
static ZCTools *_instance; //类方法,返回一个单例对象
+ (instancetype)shareTools
{
//注意:这里建议使用self,而不是直接使用类名Tools(考虑继承) return [[self alloc]init];
} //保证永远只分配一次存储空间
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
//使用GCD中的一次性代码
// static dispatch_once_t onceToken;
// dispatch_once(&onceToken, ^{
// _instance = [super allocWithZone:zone];
// }); //使用加锁的方式,保证只分配一次存储空间
@synchronized(self) {
if (_instance == nil) {
_instance = [super allocWithZone:zone];
}
}
return _instance;
} //让代码更加的严谨
- (nonnull id)copyWithZone:(nullable NSZone *)zone
{
// return [[self class] allocWithZone:zone];
return _instance;
} - (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone
{
return _instance;
} //在MRC环境下,如果用户retain了一次,那么直接返回instance变量,不对引用计数器+1
//如果用户release了一次,那么什么都不做,因为单例模式在整个程序运行过程中都拥有且只有一份,程序退出之后被释放,所以不需要对引用计数器操作
- (oneway void)release
{
} - (instancetype)retain
{
return _instance;
} //惯用法,有经验的程序员通过打印retainCount这个值可以猜到这是一个单例
- (NSUInteger)retainCount
{
return MAXFLOAT;
}

通用版本


  • 可以考虑一份单例代码在ARC和MRC环境下都适用

    (使用条件编译来判断当前项目环境是ARC还是MRC)
#if __has_feature(objc_arc)
//如果是ARC,那么就执行这里的代码1
#else
//如果不是ARC,那么就执行代理的代码2
#endif
  • 在项目里面往往需要实现很多的单例,比如下载、网络请求、音乐播放等等,单例是否可用继承呢?

    • 单例是不可继承,想一劳永逸可使用带参数的宏定义
  • 使用带参数的宏完成通用版单例模式代码

    • 注意条件编译的代码不能包含在宏定义里面
    • 宏定义的代码只用写一次,之后直接拖到项目中用就OK

#define SingleH(name) +(instancetype)share##name; //ARC
#if __has_feature(objc_arc)
#define SingleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
return _instance;\
}\
+(instancetype)share##name\
{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
return _instance;\
} #else
//MRC
#define SingleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
return _instance;\
}\
+(instancetype)share##name\
{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
-(oneway void)release\
{\
}\
\
-(instancetype)retain\
{\
return _instance;\
}\
\
-(NSUInteger)retainCount\
{\
return MAXFLOAT;\
}
#endif

iOS中的单例模式的更多相关文章

  1. 浅谈iOS中的单例模式

    iOS中的单例模式     就我本身理解而言,我认为的单例:单例在整个工程中,就相当于一个全局变量,就是不论在哪里需要用到这个类的实例变量,都可以通过单例方法来取得,而且一旦你创建了一个单例类,不论你 ...

  2. 在ios中使用单例模式编程

    本文转载至 http://blog.csdn.net/remote_roamer/article/details/7107007     1.    @implementation Singleton ...

  3. ios 开发之单例模式

    在iOS开发中,有很多地方都选择使用单例模式.有很多时候必须要创建一个对象,并且不能创建多个,用单例就为了防止创建多个对象.单例模式的意思就是某一个类有且只有一个实例.单例模式确保某一个类只有一个实例 ...

  4. iOS中的事件响应链、单例模式、工厂模式、观察者模式

    学习内容 欢迎关注我的iOS学习总结--每天学一点iOS:https://github.com/practiceqian/one-day-one-iOS-summary iOS中事件传递和相应机制 i ...

  5. iOS设计模式之单例模式

    单例模式 基础理解 所有类都有构造方法,不编码则系统默认生成空的构造方法,若有显示定义的构造方法,默认的构造方法就会失效. 单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全 ...

  6. iOS 中SQLite数据库操作

    在iOS中实现SQLite数据库的操作:1.导入框架(libsqlite3.0.tbd) 2.导入头文件<sqlite3.h> 3.实现数据的增删改查 实现简单 SQLite数据库操作 的 ...

  7. iOS开发之单例模式

    1.概述 单例模式是一种常用的软件设计模式,通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源. 如果希望系统中某个类的对象只能存在一个,单例模 ...

  8. OS X 和iOS 中的多线程技术(下)

    OS X 和iOS 中的多线程技术(下) 上篇文章中介绍了 pthread 和 NSThread 两种多线程的方式,本文将继续介绍 GCD 和 NSOperation 这两种方式.. 1.GCD 1. ...

  9. IOS中的单例设计模式

    单例设计模式是IOS开发中一种很重要很常用的一种设计模式.它的设计原理是无论请求多少次,始终返回一个实例,也就是一个类只有一个实例.下面是苹果官方文档中关于单例模式的图片: 如图所示,左边的图是默认的 ...

随机推荐

  1. poj 1474 Video Surveillance - 求多边形有没有核

    /* poj 1474 Video Surveillance - 求多边形有没有核 */ #include <stdio.h> #include<math.h> const d ...

  2. android自定义之 5.0 风格progressBar

    最近做项目,用到了ProgressBar ,就想到了要使用Android5.0 的效果,就随手实现了一下. 效果图: 大概的思路: 1. 圆圈通过Canvas去绘制 2.圆圈的动画通过Animator ...

  3. DDD:Command模式的好处

    背景 会有朋友问我为啥用命令模式(Command Pattern)组织应用层,先看看MartinFowler咋说:http://martinfowler.com/bliki/CommandOrient ...

  4. bootstrap插件学习-bootstrap.scrollspy.js

    先看bootstrap.dropdown.js的结构 function ScrollSpy(){} //构造函数 ScrollSpy.prototype = {} //构造器的原型 $.fn.scro ...

  5. EPANET头文件解读系列9——VARS.H

    /*************************************************************************            Global Variabl ...

  6. 将form表单元素转为实体对象 或集合 -ASP.NET C#

    简介: 做WEBFROM开发的同学都知道后台接收参数非常麻烦 虽然MVC中可以将表单直接转为集实,但不支持表单转为 LIST<T>这种集合 单个对象的用法: 表单: <input n ...

  7. ASP.NET WebForm与MVC优缺点

    发表于我的个人网站中,请点击阅读!

  8. IOS开发UI基础之UIScrollView

    什么是UIScrollView ● 移动设备的屏幕⼤大⼩小是极其有限的,因此直接展⽰示在⽤用户眼前的内容也相当有限 ● 当展⽰示的内容较多,超出⼀一个屏幕时,⽤用户可通过滚动⼿手势来查看屏幕以外的内容 ...

  9. Scrum4.0

    1.准备看板. 形式参考图4. 2.任务认领,并把认领人标注在看板上的任务标签上. 先由个人主动领任务,PM根据具体情况进行任务的平衡. 然后每个人都着手实现自己的任务. 3.为了团队合作愉快进展顺利 ...

  10. 安装jdk For Windows

    1.下载JDK查看最新:http://www.oracle.com/technetwork/java/javase/downloads/index.html根据操作系统选择合适的JDK进行下载2.运行 ...