iOS常用设计模式之单例模式

image

引言

在很多时间,singleton定义为“有且仅有一个元素的集合”,所以不管那个对象到底有多大,每次我们拿这个对象时都是同一个。在什么情况下会需要单例以及单例在Objective-C中如何实现呢?本节Abel将与您一起探讨一些有关singleton的知识。

目录

  • 1、什么是单例模式
  • 2、什么时候用单例模式
  • 3、Objective-C中单例模式的实现
  • 4、线程安全
  • 5、总结

1、什么是单例模式

单例模式几乎是设计模式中最简单的了。这一模式的意图是使得类的一个对象成为系统中唯一的实例。要实例这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。我们可以用工厂方法来限制实例化过程。这个方法应该是一个静态的方法(类方法),因为让类的实例去生成另一个唯一实例毫无意义。

2、什么时候使用单例模式

1、类只能有一个实例,而且必须从一个为人熟知的访问点对其访问。
2、这个唯一的实例只能通过子类化进行扩展,而且扩展的对象不会破坏客户端代码。

3、Objective-C中单例模式的实现

在《设计模式》一书中的原始示例中,单例模式的C++例子如下所求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Singleton
{
  public:
      static Singleton *Instance();
  protected:
      Singleton();
  private:
      static Singletion * _instance;
}

Singleton *Singleton::Instance()
{
  if(_instance == 0)
  {
      instance = new Singleton;
  }
  return _instance;
}

知道C++语言的人都能看出来,在上面的C++代码Instance()方法中,检查静态的_instance实例变量,看它是否为0,如果是,会生成一个新的Singleton对象,然后将实例返回,现在我们把它改造成Objective-C版。

那么用Objective-C如何实现单例模式呢?下面我们来新建一个Singleton类,在Singleton.h中实现如下

1
2
3
@interface Singleton : NSObject
+ (Singleton *) sharedInstance;
@end

在Singleton.m

1
2
3
4
5
6
7
8
9
10
@implementation Singleton
static Singleton * sharedSingleton = nil;

+ (Singleton *) sharedInstance  {
  if (sharedSingleton == nil) {
      sharedSingleton = [[Singleton alloc] init];
  }
  return sharedSingleton;
}
@end

按照C++改造成Objective-C就完成了。如果真是这样的话,那么单例模式真的是太简单了,但实际上,需要克服一些障碍,才能让单例模式更可靠,可以真正放心地应用于程序中。如果需要实现一个“严格”的单例模式,还需要面对两个主要的障碍。

发起调用的对象不能以其他分配方式实例化对象。否则,就有可能创建多个单例实例。
对单例对象实例化的限制应该与引用计数内存模型共存。

下面我对Singleton.m的进行改进

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@implementation Singleton
 static Singleton * sharedSingleton = nil;
+ (Singleton *) sharedInstance  {
  if (sharedSingleton == nil) {
      sharedSingleton = [[super allocWithZone:NULL] init];
  }
  return sharedSingleton;
}

+ (id) allocWithZone:(struct _NSZone *)zone  {
  return [[self sharedInstance] retain];
}

- (id) copyWithZone:(NSZone *) zone  {
  return self;
}

- (id) retain  {
  return self;
}

- (NSUInteger) retainCount  {
  return NSUIntegerMax;
}


- (void) release  {
//  
}

- (id) autorelease  {
  return self;
}
@end

也许你注意到了,我重载了allocWithZone:,保持了从sharedInstance方法返回的单例对象,使用者哪怕使用alloc时也会返回唯一的实例(alloc方法中会先调用allocWithZone:创建对象)。而retain等内存管理的函数也被重载了,这样实现了合适的内存管理原则。

4、线程安全

如果单例对象要由多个线程访问,那么使它的线程安全至关重要。例子中的Singleton类只能胜任一般用途。要让它线程安全,需要在sharedSingleton静态实例的nil检查周围加入一些@synchronized()程序块或者NSLock实例。如果有其他的属性需要保护,也可以把它们声明为atomic型。

5、总结

到此,单例模式的讲解就到些结束了。不管在哪个平台开发,单例模式都极为常用。如果单例模式还有不懂的地方,可以给我留言。





Comments