一、简介:
(1)单例模式是一种常用的软件设计模式,在应用这个模式时,单例对象的类必须保证只有一个实例存在。
(2)通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。
(3)如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
(4)iOS中最常见的单例:
1>、UIApplication
2>、UIAccelerometer
3>、NSUserDefaults:读取应用程序设置项目。
4>、NSNotificaionCenter:提供信息广播通知。
5>、NSFileManager:提供访问文件系统的通用操作,可以定位、创建、复制文件和文件夹。
6>、NSBundle:提供动态加载(或卸载)可执行代码、定位资源文件以及资源本地化、访问文件系统等。
二、为什么需要单例模式
(1)整个应用程序只能有一个实例。例如:UIApplication类:当应用程序启动时,应用的状态由UIApplication类的一个实例维护,这个实例代表了整个“应用程序对象”,实现应用程序�中的一些�共享资源的访问和状态的保持等。
(2)在iOS应用整个生命周期中,只需要一个实例。例如:UIAccelerometer类:实时获得重力加速计数据,保持x,y,z轴的状态。这个实例只需要一个实例,多个实例完全没有意义(一台设备还能产生2个加速度?),只会占用内存。
三、怎么保证只有一个实例呢
首先我们会想到,用个if语句判断类是否已经被实例化。如果未被实例化,则实例化。否则直接返回。但是如果单例对象由多个线程访问呢?所有线程安全至关重要,单例模式一般会封装一个静态属性,并提供静态实例的创建方法。
四、在iOS中什么时候使用单例模式
(1)如果说创建一个对象会耗费很多系统资源,那么此时采用单例模式,因为只需要一个实例,会节省alloc的时间
(2)在iOS开发中,如果很多模块都要使用同一个变量,如果把该变量放入单例类,则所有访问该变量的调用变得很容易;否则只能通过一个模块传递给另外一个模块,增加了风险和复杂度
五、单例模式优缺点
优点:可以阻止其他对象实例化单例对象的副本,从而确保所有对象都访问唯一实例;
缺点:单例对象一旦建立,对象指针是保存在静态区的,单例对象在堆中分配的内存空间,会在应用程序终止后才会被释放;
提示:只有确实需要唯一使用的对象才需要考虑单例模式,不要滥用单例。
六、代码实例
// Singleton.h
#import
@interface Singleton : NSObject
@property(nonatomic,strong)NSString*name;
//单例方法
+(Singleton*)defaultManager;
@end
// Singleton.m
#import "Singleton.h"
@implementation Singleton
//单例类的静态实例对象,因对象需要唯一性,故只能是static类型
static Singleton *defaultManager = nil;
/** 单例模式对外的唯一接口,用到的dispatch_once函数在一个应用程序内只会执行一次,且dispatch_once能确保线程安全。
* (1)dispatch_once 是线程安全的,能够做到在多线程的环境下Block中的代码只会被执行一次,而且还是线程同步�的。
*/
+(Singleton*)defaultManager
{
static dispatch_once_t token;
dispatch_once(&token,^{
if (defaultManager==nil) {
defaultManager=[[self alloc]init];
}
});
return defaultManager;
}
/** allocWithZone方法是对象分配内存空间时,最终会调用的方法,重写该方法,保证只会分配一个内存空间。
* (1)覆盖该方法主要确保当用户通过[[Singleton alloc] init]创建对象时对象的唯一性,alloc方法会调用该方法,只不过zone参数默认为nil。
* (2)因为该类覆盖了allocWithZone方法,所以只能通过其父类分配内存,即[super allocWithZone:zone]。
*/
+(id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t token;
dispatch_once(&token,^{
if (defaultManager==nil) {
defaultManager=[super allocWithZone:zone];
}
});
return defaultManager;
}
/**自定义初始化方法,本例中只有name这一属性*/
-(instancetype)init
{
self=[super init];
if (self) {
self.name=@"Singleton";
}
return self;
}
/** 覆盖该方法主要确保当用户通过copy方法产生对象时对象的唯一性*/
- (id)copy
{
return self;
}
/** 覆盖该方法主要确保当用户通过mutableCopy方法产生对象时对象的唯一性*/
- (id)mutableCopy
{
return self;
}
/** 自定义描述信息,用于log详细打印*/
- (NSString *)description
{
return [NSString stringWithFormat:@"memeory address:%p,property name:%@",self,self.name];
}
@end
然后我们使用这个单例:
Singleton *defaultManagerSingleton =[Singleton defaultManager];
NSLog(@"defaultManager:%@",defaultManagerSingleton);
Singleton *allocSingleton = [[Singleton alloc] init];
NSLog(@"allocSingleton:%@",allocSingleton);
Singleton *copySingleton= [allocSingleton copy];
NSLog(@"copySingleton :%@",copySingleton);
Singleton *mutebleCopySingleton = [allocSingleton mutableCopy];
NSLog(@"mutablecopy :%@",mutebleCopySingleton);
打印结果:
2016-11-30 13:43:21.535 mySubTest[8600:114983] 568.000000
2016-11-30 13:43:24.216 mySubTest[8600:114983] defaultManager:memeory address:0x7ffa1772cc30,property name:Singleton
2016-11-30 13:43:24.217 mySubTest[8600:114983] allocSingleton:memeory address:0x7ffa1772cc30,property name:Singleton
2016-11-30 13:43:24.217 mySubTest[8600:114983] copySingleton :memeory address:0x7ffa1772cc30,property name:Singleton
2016-11-30 13:43:24.218 mySubTest[8600:114983] mutablecopy :memeory address:0x7ffa1772cc30,property name:Singleton
从打印结果来看通过 [Singleton defaultManager]、[[Singleton alloc] init]、[allocSingleton copy]、[allocSingleton mutableCopy]这四种方法生成的对象地址都是0x7ffa1772cc30,即表明对象是同一个,也就实现了严格单例模式,加上GCD是线程安全的所以在多线程中也能保证对象的唯一性。