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开发中的设计模式还有很多,其他的设计模式以后会慢慢讲到。

0 0
原创粉丝点击