iOS开发之单例模式
来源:互联网 发布:2016年淘宝9月大促时间 编辑:程序博客网 时间:2024/06/14 20:13
在讲到GCD的其他用法的时候,其中有一个用法是让代码在程序运行期间只执行一次。这种功能可以帮助我们实现iOS开发中的一种设计模式:单例模式。
单例模式
一个类在整个程序运行过程中只有一个实例。
单例模式的作用
可以保证在程序运行过程中,一个类只有一个实例,而且该实例易于供外界访问。从而方便第控制了实例个数,并节约系统资源。
单例模式使用场合
在整个应用程序中,共享一份资源(这份资源只需要创建初始化一次)
单例模式在ARC和非ARC环境下得写法有所不同,需要编写两套不同的代码。如果将单例写成宏的形式,可以使用__has_feature(objc_arc)宏判断是否为ARC环境。
#if __has_feature(objc_arc)// 是ARC#else// 非ARC#endif
ARC中的单例实现
1. 在.m文件中保留一个全局的static的实例
static id _instance
2. 重写allocWithZone:方法(alloc方法内部会自动执行该方法,在该方法中分配唯一内存),在这里创建唯一的实例(注意线程安全)
+ (id)allocWithZone:(struct _NSZone *)zone{ // 里面的代码永远只执行1次 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); // 返回对象 return _instance;}
或者:
+ (id)allocWithZone:(struct _NSZone *)zone{ // 里面的代码永远只执行1次 @synchronized(self) {// 加锁,防止别的线程同时访问if (!_instance) { _instance = [super allocWithZone:zone]; } } // 返回对象 return _instance;}
3. 提供一个类方法让外界获得唯一的实例
+ (instancetype)sharedInstance{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }) return _instance;}
或者:
+ (instancetype)sharedInstance{ @synchronized(self) {if (!_instance) { _instance = [[self alloc] init]; } } return _instance;}
4. 再实现copy方法(copy方法内部会自动执行copyWithZone:方法,因为实例就一个只要返回自身即可)
+ (id)copy{ return _instance;}
非ARC中的单例实现
在非ARC中(MRC),单例模式的实现除了实现上面的代码之外,还要比ARC多出几个步骤。
在非ARC环境下,需要我们自己管理内存,需要实现以下内存管理方法:
- (id)retain { return self;// 或return _instance}- (NSUInteger)retainCount { return 1;}- (oneway void)release {}- (id)autorelease { return self;// 或return _instance}
下面我们就用一个例子来实现一下载ARC和非ARC下的单例
场景:现在在项目中有10个控制器页面需要播放同一段音乐。要是每个控制器器里面都创建一个新的对象来播放该音乐,就显得太繁琐,内存占用也大。那么这个时候就可以使用单例模式来解决这个问题。
创建一个HXMusicTool类(整个应用程序中只有一个实例对象),该类的作用是播放一段音乐。(ARC)2. 在HXMusicTool.m文件中实现和重写以下方法
#import "HXMusicTool.h"@implementation HXMusicTool// 声明一个全局的实例变量static id _instance;+ (instancetype)shareMusicTool { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance;}/** * 重写allocWithZone:方法(alloc方法中会自动调用该方法)来分配唯一的内存空间 */+ (instancetype)allocWithZone:(struct _NSZone *)zone { // block中的代码只会执行一次 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); // 返回分配内存后的对象 return _instance;}/** * 重写copy方法,保证copy出来的对象也是实例对象 */+ (id)copy{ return _instance;}@end
3. 在HXMusicTool.h文件中提供shareMusicTool外部接口,供外界访问实例对象
#import <Foundation/Foundation.h>@interface HXMusicTool : NSObject// 外部接口,供外界访问实例变量+ (instancetype)shareMusicTool;@end
4. 在ViewController中使用HXMusicTool类
#import "ViewController.h"#import "HXMusicTool.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; // tool1,tool2通过alloc创建 HXMusicTool *tool1 = [[HXMusicTool alloc] init]; HXMusicTool *tool2 = [[HXMusicTool alloc] init]; // tool3,tool4通过提供的外部接口创建 HXMusicTool *tool3 = [HXMusicTool shareMusicTool]; HXMusicTool *tool4 = [HXMusicTool shareMusicTool]; HXMusicTool *tool5 = [HXMusicTool copy]; // 打印四个对象的内存地址 NSLog(@"\n1 = %p\n2 = %p\n3 = %p\n4 = %p\n5 = %p", tool1, tool2, tool3, tool4, tool5);}@end
打印结果:
相同的内存地址。说明四个对象是一个实例。这就做到了在整个应用程序中,不管使用什么方法来创建对象都是同一个实例对象。
在非ARC环境下实现上面的需求,只需要在HXMusicTool.m文件中再实现以下方法即可
- (id)retain { return self;// 或return _instance}- (NSUInteger)retainCount { return 1;}- (oneway void)release {}- (id)autorelease { return self;// 或return _instance}
这就保证了在程序运行期间,实例对象一旦创建就会一直存在,且唯一。
现在项目的开发大部分都在ARC和非ARC混合环境下进行的,那么单例模式如何同时适用ARC和非ARC环境。
下面就提供一种解决方案:在实现单例模式的代码写成宏,再使用宏判断当前是否是ARC环境,并在不同环境下实现不同的代码。
以下是同时适用ARC和非ARC的单例模式(宏)
// ## : 连接字符串和参数#define singleton_h(name) + (instancetype)shared##name;#if __has_feature(objc_arc) // ARC#define singleton_m(name) \static id _instance; \+ (id)allocWithZone:(struct _NSZone *)zone \{ \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [super allocWithZone:zone]; \ }); \ return _instance; \} \ \+ (instancetype)shared##name \{ \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [[self alloc] init]; \ }) return _instance; \} \+ (id)copyWithZone:(struct _NSZone *)zone \{ \ return _instance; \}#else // 非ARC#define singleton_m(name) \static id _instance; \+ (id)allocWithZone:(struct _NSZone *)zone \{ \static dispatch_once_t onceToken; \dispatch_once(&onceToken, ^{ \_instance = [super allocWithZone:zone]; \}); \return _instance; \} \\+ (instancetype)shared##name \{ \static dispatch_once_t onceToken; \dispatch_once(&onceToken, ^{ \_instance = [[self alloc] init]; \}); \return _instance; \} \\- (oneway void)release \{ \\} \\- (id)autorelease \{ \return _instance; \} \\- (id)retain \{ \return _instance; \} \\- (NSUInteger)retainCount \{ \return 1; \} \\+ (id)copyWithZone:(struct _NSZone *)zone \{ \return _instance; \}#endif
注意:后面添加\是说明下一行也是宏的一部分
这就是iOS开发单例设计模式的实现,其实IOS开发中的设计模式还有很多,其他的设计模式以后会慢慢讲到。
- iOS开发模式之单例模式
- IOS开发之----单例模式详解
- IOS开发之----单例模式详解
- IOS开发之----单例设计模式
- iOS开发之单例模式
- iOS开发之单例模式
- iOS开发之单例模式
- iOS 开发之单例模式
- iOS开发之单例模式
- iOS开发之单例模式
- IOS开发 单例模式
- iOS开发-单例模式
- ios开发 单例模式
- iOS开发-单例模式
- IOS开发基础之──单例模式
- IOS开发基础之──单例模式
- iOS开发之单l例模式(Singleton)
- iOS开发之单例模式的写法
- Install LaTeX in Ubuntu Linux
- MySQL中使用SQL语句查看某个表的编码
- Incompatible integer topointer conversion assigning to 'BOOL *' (aka 'signed char *') from'BOOL' (a
- windows下批量修改文件名称
- Tomcat Xms Xmx PermSize MaxPermSize 区别 及 java.lang.OutOfMemoryError: PermGen space 解决
- iOS开发之单例模式
- 跟我一起玩Win32开发(1):关于C++的几个要点
- 【离散数学】实验四 图的随机生成及欧拉(回)路的确定
- SQLite数据库增删改查操作
- Spring:整合Struts1
- 网站压力测试
- 睡得多,会变丑变痴
- IntelliJ IDEA 14 如何运行maven程序
- html编辑页面中 跳转获取下拉列表中的选定值 jstl