单例设计模式确切的说就是一个类只有一个实例,有一个全局的接口来访问这个实例。当第一次载入的时候,它通常使用延时加载的方法创建单一实例。
提示:苹果大量的使用了这种方法。例子:[NSUserDefaults standerUserDefaults], [UIApplication sharedApplication], [UIScreen mainScreen], [NSFileManager defaultManager] 都返回一个单一对象。
你可能想知道你为什么要关心一个类有多个的实例。代码和内存都很便宜,不是吗?
在一些情况下,一个类只有一个实例是有意义的。例如,这里没有必要有多个登录实例,除非你一次想写入多个日志文件。或者,一个全局的配置类文件:它可以很容易的很安全的执行一个公共资源,这样的一个配置文件,要比同时修改多个配置类文件好很多。
如何使用单例模式
请看下面的图片
上面的图片显示的是一个登录类,它有一个属性(这个单一实例),有两个方法:sharedInstance 和 init。
首先一个客户端(client)发送 sharedInstance 信息,但是属性 instance 还没有初始化,所以你要先给这个类创建一个实例。
然后你调用 sharedInstance,instance 会马上返回初始化的值。这个逻辑最终只会返回一个实例。
你需要执行这个模式来创建单例类来管理所有的专辑数据。
你需要注意在项目里有一个叫 API 文件夹,给你的 APP 提供服务的所有类都需要放在这里。在这个文件夹里用 iOS\Cocoa Touch\Object-C class 创建一个新类。类的名字叫 LibraryAPI,子类选择 NSObject。
打开 LibraryAPI.h 文件用下面的代码替换里面的内容:
@interface LibraryAPI: NSObject + (LibraryAPI*)sharedInstance; @end
+ (LibraryAPI*)sharedInstance { // 1 static LibraryAPI *_sharedInstance = nil;// 2 static dispatch_once_t oncePredicate;
// 3 dispatch_once(&nocePredicate, ^{ _sharedInstance = [[LibraryAPI alloc] init]; }); return _sharedInstance; }
在这个类中,声明一个静态变量来保存这个实例,保证它是一个全局可用的变量。
声明一个静态这是 dispatch_one_t,确保这些初始化代码只能被执行一次。
使用 Grand Central Dispatch(GCD)执行一个 block 来初始化 LibraryAPI 实例。这是单例设计模式的关键所在:一个类只能被实例化一次。
接下来执行 sharedInstance,在 dispatch_once block 里的代码是不会被执行的(当它已经被执行过一次后),它会返回之前创建的 LibraryAPI 实例。
提示:想了解更多关于 GCD 和使用它,请点击这里的教程 Multithreading and Grand Central Dispatch,如何使用 Blocks 在这里。
你现在有一个单例对象来管理专辑了。下一步就是创建一个类用来保存你的专辑数据了。
用 iOS\Cocoa Touch\Object-C class 在 API 文件夹下创建一个新的类,名字叫 PersistencyManager,子类选择 NSObject。
打开 PersistencyManager.h,在顶部引入面文件:
#import "Album.h"
然后在 @interface 后面加入下面代码:
- (NSArray *)getAlbums; - (void)addAlbums:(Album*)album atIndex:(int)index; - (void)deleteAlbumAtIndex:(int)index;
打开 PersistencyManager.m,在 @implementation 上面添加如下代码:
@interface PersistencyManager () { NSMutableArray *albums; }
现在在 @implementation 下面添加实现代码:
- (id)init { self = [super init]; if (self) { albums = [NSMutableArray arrayWithArray:@[[[Album alloc] initWithTitle:@"Best of Bowie" artist:@"David Bowie" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_david%20bowie_best%20of%20bowie.png" year:@"1992"], [[Album alloc] initWithTitle:@"It's My Life" artist:@"No Doubt" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_no%20doubt_its%20my%20life%20%20bathwater.png" year:@"2003"], [[Album alloc] initWithTitle:@"Nothing Like The Sun" artist:@"Sting" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_sting_nothing%20like%20the%20sun.png" year:@"1999"], [[Album alloc] initWithTitle:@"Staring at the Sun" artist:@"U2" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_u2_staring%20at%20the%20sun.png" year:@"2000"], [[Album alloc] initWithTitle:@"American Pie" artist:@"Madonna" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_madonna_american%20pie.png" year:@"2000"]]]; } return self; }
现存在 PersistencyManager.m 添加下面三个方法:
- (NSArray*)getAlbums { return albums; }- (void)addAlbum:(Album*)album atIndex:(int)index { if (albums.count >= index) [albums insertObject:album atIndex:index]; else [albums addObject:album]; }
- (void)deleteAlbumAtIndex:(int)index { [albums removeObjectAtIndex:index]; }
Build 你的项目,确保所有的代码都能正确编译。
单例模式的使用场合
类只能有一个实例,并且必须从一个为人数值的访问点对其访问。
这个唯一的实例只能通过子类化进行拓展,并且拓展的对象不会破坏客户端代码。
在Objective-C中方法都是公有的,而且OC的语言本身是动态类型的,因此所有类都可以相互发送对方的消息。,并且Cocoa框架使用计数的内存管理方式来维护对象的内存中的生存期。
下面让我们看一下OC当中的单例模式的写法,首先单例模式在ARC\MRC环境下的写法有所不同,需要编写2套不同的代码
可以用宏判断是否为ARC环境#if _has_feature(objc_arc)
#else //MRC #endif
ARC中单例模式的实现
在 .m中保留一个全局的static的实例
static id _instance; //重写allocWithZone:方法,在这里创建唯一的实例(注意线程安全) + (instancetype)allocWithZone:(struct _NSZone *)zone { @synchronized(self) { if (_instance == nil) { _instance = [super allocWithZone:zone]; } } return _instance; }
+ (instancetype)sharedInstanceTool{ @synchronized(self){ if(_instance == nil){ _instance = [[self alloc] init]; } } return _instance; }
实现copyWithZone:方法
-(id)copyWithZone:(struct _NSZone *)zone{ return _instance; }
方法二:
+(instancetype)sharedInstance { static WMSingleton *singleton = nil; if (! singleton) { singleton = [[self alloc] initPrivate]; } return singleton; }- (instancetype)init { @throw [NSException exceptionWithName:@"这个是个单例" reason:@"应该这样调用 [WMSingleton sharedInstance]" userInfo:nil]; return nil; } //实现自己真正的私有初始化方法 - (instancetype)initPrivate { self = [super init]; return self; }
static WMObject *_instance; + (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); return _instance; }+ (instancetype)sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance; }
- (id)copyWithZone:(NSZone *)zone { return _instance; }
// .h文件 #define WMSingletonH(name) + (instancetype)shared##name;// .m文件 #define WMSingletonM(name) \ static id _instance; \ \ + (instancetype)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:(NSZone *)zone \ { \ return _instance; \ }
//.h类 //引入这个宏文件 #import "WMSingleton.h" @interface WMObject : NSObject WMSingletonH(object) @end //.m类@implementation WMObject WMSingletonM(Car) @end
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:notice#nhooo.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。