Objective-C和Swift实现单例的几种方式
在Swift开发中,我们对于跨类调用的变量常量,因为并没有OC中使用的全局头文件中写宏的形式,我们一般采用在类外定义全局变量/常量的形式来跨类调用。而问题在于目前写的项目需要在新添加的OC写的功能模块中调用Swift的全局变量,这样编译器是没办法帮你调到的。为了解决这个问题,我考虑来写一个Swift单例来保存全局变量,并由OC的类来调取数据。
ps:差点忘记文章的初衷了。如果大家有好的用OC调取Swift的全局变量的方法,希望可以提供方法或网址,感激不尽。
在iOS设计中,单例这种设计模式经常用到,也是是设计模式中最简单的一种,甚至有些模式大师都不称其为模式,称其为一种实现技巧。原因是设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,与其他对象之间并不抽象。但不可否认的是,单例已经方方面面的融入到我们的项目中来了,极为方便。
那我们究竟在什么时候需要使用单例设计模式呢?
顾名思义,当你只需要一个实例的时候需要使用单例,如UIApplication.sharedApplication() 等 ,就好比windows的任务管理器,回收站等等都是只能同时存在一个。
一.OC中的单例设计模式有三种。简单介绍一下。
首先,我们要创建一个继承于NSObject的类。在这个类的 .h头文件中,我们声明一个加方法。命名一般如下:
+ (SingleInstance *)sharedInstance;
随后在.m中实现这个方法。这里有三种形式,相对来说,安全和效率等级越来越高。
1.直接创建
static SingleInstance *singleOne;
+ (SingleInstance *)sharedInstance {
if (!singleOne) {
singleOne = [[SingleInstance alloc] init];
}
return singleOne;
}
非常好理解。创建一个静态的指针;如果指针没有指向对象,那么创一个对象并让指针持有该对象;最后返回这个指针持有的对象。因为静态,所以指针持有的对象不会被释放,也就保证了每次调取这个方法都只会返回一个对象,实现了单例的目的。
不难看出,这种做法虽然简单明了,并且逻辑上并没有什么错误,但它并没有考虑线程安全的问题。在我们学习了多线程之后,我们就会考虑这段代码的安全性问题了。假设两条线程同时调用这段代码,并且若此时对象并未被创建,那么会创建几个对象?而若创建了多个对象,很明显与单例设计思想相违背。这样我们就有了以下的做法。
2.加互斥锁
根据我们刚才的分析,我们很自然会想到这样的做法:既然要防止多个线程同时访问这段代码,我们加个互斥锁,让线程们排队访问,不就解决了吗?
static SingleInstance *singleTwo;
+ (SingleInstance *)sharedInstance {
@synchronized (self) {
if (!singleTwo) {
singleTwo = [[SingleInstance alloc] init];
}
}
return singleTwo;
}
更加简单粗暴。一言不合就上锁,这段代码只能排队执行,一个一个来。这样完美的保证了单例只有一个对象的要求。
但是更大的问题出现了,我确实只执行了一次,但是在第二次使用这个方法的时候,if判断语句还是需要走啊?大家创建完对象仍然一点一点排队走,太影响效率了吧?
所以,强迫症如我们程序猿,是不允许这样耗费线程资源还执行效率低下的事情发生的。更好的方法来了。
ps:互斥锁相关再解释一下,与多线程并发有关,意义基本在于多条线程访问同一时间访问同一段代码的时候要按顺序执行,不能并发。这样能有效解决多线程的安全问题。详情请百度。
3.使用GCD技术
static SingleInstance *singleThree;
+ (SingleInstance *)sharedInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleThree = [[SingleInstance alloc] init];
});
return singleThree;
}
使用 dispatch_once 这个函数来创建对象,这样就保证了只有一个对象。问题解决。
ps:dispatch_once是GCD中的一个对象,这个函数可以保证不管被调用几次,内部block只会执行一次,来保证代码执行的唯一性。
综上,OC使用的单例方式一般就这三种,而我们使用的一般是第三种,安全性更高,执行效率更好。
二.下面看看swift中的几种实现方式:
1.
class SingleOne {
//单例
static let shareSingleOne = SingleOne()
}
let singleOne = SingleOne.shareSingleOne
ps:代码编辑器中没有找到Swift语言,很尴尬..用OC凑活看吧
一句话搞定,静态常量。所有地方用到的都是同一个。调用直接使用类名调取常量名即可。
2.
class SingleTwo {
//单例
class func shareSingleTwo() -> SingleTwo {
struct Singleton{
static var onceToken: dispatch_once_t =
static var single: SingleTwo?
}
dispatch_once(&Singleton.onceToken, {
Singleton.single = shareSingleTwo()
})
return Singleton.single!
}
}
let singleTwo = SingleTwo.shareSingleTwo()
本质上与OC第三种方法一样,都是使用dispatch_once保证其中的代码只执行一次。中间用了一个结构体来保存两个静态变量,也可以不使用这个结构体。
3.
import Foundation //全局的常量
let single = SingleThree() class SingleThree { class var sharedInstance : SingleThree { return single
}
} let singleThree = SingleThree.sharedInstance
4.
import Foundation
class SingleFour {
static var sharedInstance : SingleFour {
struct Static {
static let instance: SingleFour = SingleFour()
}
return Static.instance
}
}
let singleFour = SingleFour.sharedInstance
这次我们是在方法内定义静态常量。
大概的创建单例的方式就是这些了。希望大家能有所收获。
Objective-C和Swift实现单例的几种方式的更多相关文章
- swift实现单例的四种方式
单例模式 单例模式是设计模式中最简单的一种,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象. 当你只需要一个实例的时候需要使用单例 ...
- Java实现单例的5种方式
1. 什么是单例模式 单例模式指的是在应用整个生命周期内只能存在一个实例.单例模式是一种被广泛使用的设计模式.他有很多好处,能够避免实例对象的重复创建,减少创建实例的系统开销,节省内存. 2. 单例模 ...
- java单例的几种实现方法
java单例的几种实现方法: 方式1: public class Something { private Something() {} private static class LazyHolder ...
- iOS单例的两种实现
单例模式算是开发中比较常见的一种模式了.在iOS中,单例有两种实现方式(至少我目前只发现两种).根据线程安全的实现来区分,一种是使用@synchronized,另一种是使用GCD的dispatch_o ...
- objc单例的两种安全实现方案
所有转出博客园,请您注明出处:http://www.cnblogs.com/xiaobajiu/p/4122034.html objc的单例的两种安全实现方案 首先应该知道单例的实现有两大类,一个是懒 ...
- asp.net mvc表单提交的几种方式
asp.net MVC中form提交和控制器接受form提交过来的数据 MVC中form提交和在控制器中怎样接受 1.cshtml页面form提交2.控制器处理表单提交数据4种方式方法1:使用传统的R ...
- Form 表单提交的几种方式
简单的总结一下form表单提交的几种方式:1.最简单的方式 就用form的submit提交方式,这种提交方式是不需要回调函数的 这种方式最近到一个form提供action路径后台接受就可以< ...
- iOS开发——Swift篇&单例的实现
Swift实现单例模式 Swift实现单例模式 由于Swift语言弱化了struct和class之间的界限,这里我分别给出自己写的两种的单例实现 class版本: class SwiftSinglet ...
- swift学习 - 单例实现(singleton)
swift中实现单例的方式 class LGConfig: NSObject { static let instance = LGConfig() private override init() { ...
随机推荐
- 面试题-Java Web-Servlet部分
1.什么是Servlet? Servlet是用来处理客户端请求并产生动态网页内容的Java类.Servlet主要是用来处理或者是存储HTML表单提交的数据,产生动态内容,在无状态的HTTP协议下管理状 ...
- [Jmeter]jmeter之脚本录制与回放,优化(windows下的jmeter)
一.录制脚本: 1.启动jmeter 2.添加线程组 3.添加http代理 4.配置代理 a.jmeter侧(注意:lest plan content这里需要选择目标控制器,本文即测试计划中需要选择的 ...
- sim808模块收发送短信
一,简介 SIM 808发送短信分text模式和PDU模式.text模式已ascii码发送短信,这种模式比较简单,发送命令AT+CMGF=1就可以发送短信,而PDU模式比较复杂,首先发送命令AT+CM ...
- Learning from the CakePHP source code - Part I
最近开始痛定思痛,研究cakephp的源码. 成长的路上从来没有捷径,没有小聪明. 只有傻傻的努力,你才能听到到成长的声音. 下面这篇文章虽然过时了,但是还是可以看到作者的精神,仿佛与作者隔着时空的交 ...
- 移动端rem适配问题
将下面这段代码,放在头部的script标签里,可解决字体适配问题 比例是28px = 1rem function __setFontSize__(){document.documentElement. ...
- css三种布局方式
第一种布局方式:标准流(文档流) 标准流即为元素默认的显示方式.如块级元素独占一行,行内元素可以在一行显示. 第二种布局方式:浮动,float属性 浮动对应的css属性是float:left/righ ...
- Strusts2--课程笔记8
文件的和上传和下载: (1)文件的上传: Struts是通过拦截器实现文件上传的,而默认拦截器栈中包含了文件上传拦截器,故表单通过Struts2可直接将文件上传,其底层是通过apache的common ...
- Maze
Maze 题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5094 BFS+状态压缩 把身上携带钥匙的状态压缩成一个2^10的整数.这道题难在 ...
- Spring 后置处理器 PropertyPlaceholderConfigurer 类(引用外部文件)
一.PropertyPlaceholderConfigurer类的作用 PropertyPlaceholderConfigurer 是 BeanFactory 后置处理器的实现,也是 BeanFact ...
- 关于requirejs中的define的原理理解
我们已经了解到模块模式是为单例创建私有变量和特权方法的. 一个最基本的例子: var foo=(function(){ var something='cool', var another=[1,2,3 ...