单例模式是一种常用的软件设计模式。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的实例只能存在一个,单例模式是最好的解决方案。
iPhone SDK 中使用此模式的有很多,例如:
[UIApplication sharedApplication] 返回一个指向代表应用程序的单例对象的指针。[UIDevice currentDevice] 获取一个代表所使用硬件平台的对象。
将类方法与单例相结合,便可以在程序的任何地方通过对象方法获取单个实例,而无需使用指向对象的指针或保存它的实例变量。这里举个例子:
main.m
1 // 2 // main.m 3 // OCSinglePattern(单例模式) 4 // 5 // Created by Kenmu on 15/5/15. 6 // Copyright (c) 2015年 Kenmu. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 #import "SinglePatternClass.h" 11 #import "SinglePatternClass2.h" 12 13 int main(int argc, const char * argv[]) { 14 @autoreleasepool { 15 NSLog(@"普通方式实现单例模式"); 16 SinglePatternClass *objA = [SinglePatternClass defaultSinglePatternClass]; 17 objA.name = @"Kenmu的单例模式"; 18 NSLog(@"objA.name=%@", objA.name); //objA.name=Kenmu的单例模式 19 SinglePatternClass *objB = [SinglePatternClass defaultSinglePatternClass]; 20 NSLog(@"objB.name=%@", objB.name); //objB.name=Kenmu的单例模式 21 objB.name = @"Kenmu的单例模式,修改objB.name,看objA.name是否也跟随变化"; 22 NSLog(@"单例模式测试%@", [objB.name isEqualToString:objA.name] ? @"成功" : @"失败"); //单例模式测试成功 23 24 NSLog(@" GCD实现单例模式"); 25 SinglePatternClass2 *objC = [SinglePatternClass2 sharedSinglePatternClass2]; 26 objC.name = @"Kenmu的单例模式"; 27 NSLog(@"objC.name=%@", objC.name); //objC.name=Kenmu的单例模式 28 SinglePatternClass2 *objD = [SinglePatternClass2 sharedSinglePatternClass2]; 29 NSLog(@"objD.name=%@", objD.name); //objD.name=Kenmu的单例模式 30 objB.name = @"Kenmu的单例模式,修改objD.name,看objC.name是否也跟随变化"; 31 NSLog(@"单例模式测试%@", [objD.name isEqualToString:objC.name] ? @"成功" : @"失败"); //单例模式测试成功 32 } 33 return 0; 34 }
SinglePatternClass.h
1 #import <Foundation/Foundation.h> 2 3 @interface SinglePatternClass : NSObject 4 @property (strong, nonatomic) NSString *name; 5 6 /** 7 * 普通方式实现单例模式 8 * 9 * @return SinglePatternClass单例 10 */ 11 + (SinglePatternClass *)defaultSinglePatternClass; 12 @end
SinglePatternClass.m
1 #import "SinglePatternClass.h" 2 3 static SinglePatternClass *singleObj = nil; 4 @implementation SinglePatternClass 5 + (SinglePatternClass *)defaultSinglePatternClass { 6 @synchronized(self) { //这里用@synchronized实现锁,其实还可以用其他方式实现锁;例如:NSLock和C语言的pthread_mutex_t、GCD的dispatch_semaphore_t(信号量) 7 if (!singleObj) { 8 singleObj = [[SinglePatternClass alloc] init]; //这里alloc方法会调用allocWithZone:方法 9 } 10 return singleObj; 11 } 12 } 13 14 + (id)allocWithZone:(struct _NSZone *)zone { 15 @synchronized(self) { 16 if (!singleObj) { 17 singleObj = [super allocWithZone:zone]; 18 return singleObj; 19 } 20 } 21 return nil; 22 } 23 @end
SinglePatternClass2.h
1 #import <Foundation/Foundation.h> 2 3 @interface SinglePatternClass2 : NSObject 4 @property (strong, nonatomic) NSString *name; 5 6 /** 7 * GCD实现单例模式 8 * 9 * @return SinglePatternClass2单例 10 */ 11 + (SinglePatternClass2 *)sharedSinglePatternClass2; 12 @end
SinglePatternClass2.m
1 #import "SinglePatternClass2.h" 2 3 @implementation SinglePatternClass2 4 + (SinglePatternClass2 *)sharedSinglePatternClass2 { 5 static SinglePatternClass2 *singleObj2; 6 7 static dispatch_once_t onceToken; 8 dispatch_once(&onceToken, ^{ //第一个参数&onceToken是用于检查代码块是否被调用过的谓词,第二个参数是具体执行内容的代码块。dispatch_once方法中的代码块只会被执行一次,而且还是线程安全的 9 singleObj2 = [[SinglePatternClass2 alloc] init]; 10 }); 11 return singleObj2; 12 } 13 @end
代码说明:
1、synchronized 这个主要是考虑多线程的程序,这个指令可以将{ } 内的代码限制在一个线程执行,如果某个线程没有执行完,其他的线程如果需要执行就得等着。
2、allocWithZone 这个是重载的,因为这个是从制定的内存区域读取信息创建对象实例,所以如果需要的对象实例已经存在了,就需要禁止修改当前对象实例,所以返回 nil。