iOS设计模式——单例模式
单例模式用于当一个类只能有一个实例的时候, 通常情况下这个“单例”代表的是某一个物理设备比如打印机,或是某种不可以有多个实例同时存在的虚拟资源或是系统属性比如一个程序的某个引擎或是数据。用单例模式加以控制是非常有必要的。
单例模式需要达到的目的
1. 封装一个共享的资源
2. 提供一个固定的实例创建方法
3. 提供一个标准的实例访问接口
单例模式的创建
本文以创建一个MySingletonClass的单例模式为例。首先,我们需要定义一个类MySingletonClass.
- @interface MySingletonClass:NSObject {
- }
并且为其添加一个类方法(注意,这里不是实例方法)+(id)sharedInstance;一个基本的实现写法如下:
- static MySingletonClass *sharedCLDelegate = nil;
- +(MySingletonClass *)sharedInstance{
- @synchronized(self) {
- if(sharedCLDelegate == nil) {
- [[[self class] alloc] init]; // assignment not done here
- }
- }
- return sharedCLDelegate;
- }
在上面的代码中(用到了关键字@synchronized是为了保证我们的单例的线程级别的安全,可以适用于多线程模式下。)static变量sharedCLDelegate用于存储一个单例的指针,并且强制所有对该变量的访问都必须通过类方法 +(id)sharedInstance,在对 +(id)sharedInstance第一次调用时候完成实例的创建。这里值得留意一下的是,上面代码中用的是[[selfclass] alloc],而不是 [MySingletonClass alloc],一般情况下这两种写法产生同样的效果,但是这里这样做是为了更好的利用OOP的性质,[selfclass]可以动态查找并确定类的类型从而便于实现对该类的子类化。
对实例化的控制
为了完全的实现实例的单态性,必须通过一定手段来避免实例多次被创建。+(id)sharedInstance控制了单例的创建和访问,但是并不能控制其它地方的代码通过alloc方法来创建更多的实例,因此我们还要重载任何一个涉及到allocation的方法,这些方法包括 +new, +alloc,+allocWithZone:, -copyWithZone:, 以及 -mutableCopyWithZone: 另外,+(id)sharedInstance也需要稍作修改。
- + (id)hiddenAlloc
- {
- return [super alloc];
- }
- + (id)alloc
- {
- NSLog(@"%@: use +sharedInstance instead of +alloc", [[self class] name]);
- return nil;
- }
- + (id)new
- {
- return [self alloc];
- }
- +(id)allocWithZone:(NSZone*)zone
- {
- return [self alloc];
- }
- - (id)copyWithZone:(NSZone *)zone
- { // -copy inherited from NSObject calls -copyWithZone:
- NSLog(@"MySingletonClass: attempt to -copy may be a bug.");
- [self retain];
- return self;
- }
- - (id)mutableCopyWithZone:(NSZone *)zone
- {
- // -mutableCopy inherited from NSObject calls -mutableCopyWithZone:
- return [self copyWithZone:zone];
- }
- +(id)sharedInstance修改如下:
- + (MySingletonClass *)sharedInstance {
- @synchronized(self) {
- if (sharedCLDelegate == nil) {
- [[[self class] hiddenAlloc] init]; // assignment not done here
- }
- }
- return sharedCLDelegate;
- }
如果不考虑类的子类化,+hiddenAlloc这个方法可以省略。由于我们是用[selfclass]来实现类型的动态识别,用[[selfclass] hiddenAlloc]可以避免调用到被重载过的alloc方法。此外,hiddenAlloc也为可能的子类化提供了一个调用原始alloc方法的机会。上面重载过的alloc方法只是给出一个log信息并且返回nil。Copying方法里只是简单的增加了retain的计数并没有返回一个新的实例。这也正体现了单例模式的性质,因为技术上来讲,拷贝一个单例是错误的(因为是“单例”)所以在copyWithZone方法中我们给出了一个错误信息,当然也可以扔出一个exception。
单例的销毁
通常我们在 -(void)applicationWillTerminate:(UIApplication *)application方法中调用如下方法:
- + (void)attemptDealloc
- {
- if ([sharedCLDelegate retainCount] != 1)
- return;
- [sharedCLDelegate release];
- myInstance = nil;
- }
值得注意的是,上面这个attemptDealloc方法顾名思义,只是试图释放掉这个单例。如果retain的计数不为1,说明还有其他地方对该单例发送过retain消息。考虑到一个单例模式的生存周期是整个程序结束为止。所以,在程序的任何一个地方都没有必要向这个单例发送retain消息,即便是对这个单例有引用。而是调用sharedInstance方法来引用这个单例,这样做是安全的,也是合乎单例模式的技术含义的。
iOS中的单例模式应用
iOS中好几个类都是采用了单例模式,比如NSApplication, NSFontManager, NSDocumentController,NSHelpManager, NSNull,NSProcessInfo, NSScriptExecutionContext, NSUserDefaults.
如果本文有任何错误之处,欢迎拍砖指正,共同进步, 谢谢!
相关文章
- iOS AES的加密解密
- iOS buttonWithType:101 苹果私有api
- API网关的iOS SDK已经支持 IPV6
- 删除setup app 激活A7 IOS
- Xamarin.iOS编译时无法连接苹果系统
- 《iOS组件与框架——iOS SDK高级特性剖析》——第6章,第6.6节练习
- 《iOS 6核心开发手册(第4版)》——1.2节秘诀:添加简单的直接操作界面
- iOS如何实现多代理模式--OC
- Hello_IOS ios开发transform属性
- iOS点击获取短信验证码按钮
- iOS-按钮单选与多选逻辑处理
- 我用一个跨平台的网络应用程序替换了我的原生 iOS 应用程序,但没有人注意到
- ios GUI系统综述:iOS的图形绘制、动画与runloop
- iOS 如何写出更加严谨的应用
- iOS设计模式:简单工厂模式
- iOS设计模式:单例模式
- js监测设备类型【安卓,ios,苹果微信,电脑pc】
- javascript js date ios手机浏览器出现 NAN的问题解决方法
- IOS GCD 使用(三)单例模式
- mac, ios 模拟器
- iOS 静态库制作(Xcode9.0 版本)(注:亲测.a静态文件放在Unity Plugins/IOS 也可用)
- weex-platform里iOS项目打包报错/platforms/ios/../../start does not exist.
- iOS开发之网络编程--使用NSURLConnection实现文件上传
- iOS设计模式 - 命令模式
- iOS ZipArchive