设计模式,持久化,页面切换iOS 开发 iOS开发

ios-设计模式-单例

2016-05-06  本文已影响153人  我是谁重要吗

1)单例是一种编程思想,一个设计模式,与语言无关在采用了单例对象的应用程序中,需要单例类自行提供实例化单例对象,
不管实例化单例对象多少次,只有一个对象存在,这个对象是全局的,能够被整个应用程序共享,访问
2)使用单例模式时使用类提供的类方法获取单例对象,尽量不要用alloc init的方法获取单例对象
3)单例类提供类方法获取单例对象时类方法一般以sharedXX/standedXX/defaultXX开头

以下为翻译部分:

翻译自:http://www.galloway.me.uk/tutorials/singleton-classes/ 若有不精确之处,还望不吝赐教。

单例模式singleton pattern是经常使用的设计模式,它不用传递参数,就能在两个不同的代码块之间实现数据共享

比如:从任何地方调用UIApplication 的 sharedApplication方法,都会返回与当前运行程序相关的UIApplication实例。

如何实现单例类:(ARC)

#import <foundation/Foundation.h>
 
@interface MyManager : NSObject {    
    NSString *someProperty;
}
 
@property (nonatomic, retain) NSString *someProperty;
 
+ (id)sharedManager;
 
@end
#import "MyManager.h"
@implementation MyManager
@synthesize someProperty;
#pragma mark Singleton Methods
+ (id)sharedManager {
    static MyManager *sharedMyManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedMyManager = [[self alloc] init];
    });
    return sharedMyManager;
}
- (id)init {
  if (self = [super init]) {
      someProperty = [[NSString alloc] initWithString:@"Default Property Value"];
  }
  return self;
}
- (void)dealloc {
  // Should never be called, but just here for clarity really.
}
@end

上面定义了静态变量sharedMyManager 在sharedManager里只被实例化一次,GCD的dispatch_once方法保证只被创建一次,并且是线程安全的。

当然,如果不想使用GCD,可以使用下面的代码:

+ (id)sharedManager {
    static MyManager *sharedMyManager = nil;
    @synchronized(self) {
        if (sharedMyManager == nil)
            sharedMyManager = [[self alloc] init];
    }
    return sharedMyManager;
}

用下面的方法可以从任何一个地方调用这个单例

MyManager *sharedManager = [MyManager sharedManager];

单例使用广泛,比如处理CoreLocation or CoreData函数

非ARC代码:

#import "MyManager.h"
static MyManager *sharedMyManager = nil;
@implementation MyManager
@synthesize someProperty;
#pragma mark Singleton Methods
+ (id)sharedManager {
  @synchronized(self) {
      if(sharedMyManager == nil)
          sharedMyManager = [[super allocWithZone:NULL] init];
  }
  return sharedMyManager;
}
+ (id)allocWithZone:(NSZone *)zone {
  return [[self sharedManager] retain];
}
- (id)copyWithZone:(NSZone *)zone {
  return self;
}
- (id)retain {
  return self;
}
- (unsigned)retainCount {
  return UINT_MAX; //denotes an object that cannot be released
}
- (oneway void)release {
  // never release
}
- (id)autorelease {
  return self;
}
- (id)init {
  if (self = [super init]) {
      someProperty = [[NSString alloc] initWithString:@"Default Property Value"];
  }
  return self;
}
- (void)dealloc {
  // Should never be called, but just here for clarity really.
  [someProperty release];
  [super dealloc];
}
@end

以下加入我的理解:

不知你是否在上面ARC下用如下代码测试过

    MyManager *mm1 = [[MyManager alloc] init];
    MyManager *mm2 = [[MyManager alloc] init];
    MyManager *mm3 = [[MyManager alloc] init];
    NSLog(@"\n%@\n%@\n%@",mm1,mm2,mm3);
     
    MyManager *mm4 = [MyManager sharedManager];
    MyManager *mm5 = [MyManager sharedManager];
    NSLog(@"\n%@\n%@",mm4,mm5);

mm1 mm2 mm3的值(地址)是不一样的,mm4 mm5一样,重写allocWithZone就能保证mm1 mm2 mm3的值一样了。当然如果需要copy,则要重写copyWithZone

+(id)allocWithZone:(NSZone *)zone{
    @synchronized(self){
        if (sharedMyManager == nil) {
            sharedMyManager = [super allocWithZone:zone]; //确保使用同一块内存地址
            return sharedMyManager;
        }
        return sharedMyManager;
    }
}
 
- (id)copyWithZone:(NSZone *)zone {
    return self;
}

为什么实现allocWithZone、copyWithZone这两个方法?

创建对象的时候,alloc表示申请内存,init表示初始化,程序在alloc时,会在allocWithZone这个方法申请内存,我们只要在这个方法中调用sharedManager返回单例即可。这样就不会申请多次内存了。拷贝对象以此类推,同理所得,要重写copyWithZone。这样就保证了这个类只被实例化了一次。

@synchronized 保证线程安全

单例可以用来传值,系统UIApplication NSUserDefaults 就是单例类。

单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例

上一篇下一篇

猜你喜欢

热点阅读