IOS、Objective-C中单例类与半单例类

时间:2022-08-30 14:26:40

        在设计模式中有一个“单例模式”,对应的我们常常会设计“单例类”(或称单件类)。但在实际应用中,我们常常也需要使用“半单例”。下面我们具体谈谈单例和半单例,以及他们的用法和区别。

单例模式

单例模式(singleton)顾名思义,就是只有一个实例

作为对象的创建模式[GOF95], 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。

也就是说,对于一个单例类,不论实例化对象多少次,都只有一个对象实例,而且这个实例一定是一个全局的能被整个系统访问到。

下面是Objective-C中完整的单例类的实现:

Singleton.h

#import<Foundation/Foundation.h>


@interface Singleton : NSObject


+(id)shareInstance;


@end



Singleton.m

#import "Singleton.h"

static Singleton * instance = nil;

@implementation Singleton


+(id)shareInstance

{

    if(instance == nil)

    {

        instance = [[super allocWithZone:nil]init]; //super 调用allocWithZone            

    }

    return instance;

}


+(id)allocWithZone:(NSZone *)zone

{

    return [Singleton shareInstance];   

}


//可写可不写

- (id)init 

{

    if (instance) 

    {

        return instance;

    }

    

    self = [super init];

    return self;

}


-(id)copy

{

    return self;

}

- (id)copyWithZone:(NSZone *)zone

{

    return self;

}

-(id)retain

{

    return self;

}

- (oneway void)release 

{

    // Do nothing

}


- (id)autorelease 

{

    return self;

}


- (NSUInteger)retainCount 

{

    return NSUIntegerMax;

}

@end



解释说明:

1.static Singleton * instance = nil;

静态全局变量,始终指向实例化出的对象。

2.+(id)shareInstance;

外界初始化得到单例类对象的唯一借口,这个类方法返回的就是instance,即类的一个对象,

如果instance为空,则实例化一个对象,如果不为空,则直接返回。这样保证了实例的唯一。

3.-(id)copy;

- (id)copyWithZone:(NSZone *)zone;

这两个方法是为了防止外界拷贝造成多个实例,保证实例的唯一性。

4.-(id)retain;

因为只有一个实例对象,所以retain不能增加引用计数。

5.- (NSUInteger)retainCount;

因为只有一个实例对象,设置默认引用计数。这里是取的NSUinteger的最大值,当然也可以设置成1或其他值。

6.- (onewayvoid)release;

oneway void是用于多线程编程中,表示单向执行,不能“回滚”,即原子操作。


半单例

1.半单例不同于单例,它可以实例化多个对象。

2.在程序中系统要求能访问到这个类的当前对象实例。

比如说:我们对于一个ViewController,我们可以实例化多个。在ViewController中,我们给他添加了很多视图View。

这些View中,当与用户发生某个交互时,我们由需要向Controller发送消息,实现响应操作。那么,View必须能找到当前的ViewController。这时,我们可以将ViewController设置成一个半单例类。


以“翻书”程序为例:这里涉及到两个类LeavesViewController 和LeavesView

显然,我们是在LeavesViewController中添加多个LeavesView实现多页效果,

当判断出LeavesView翻到最后一页时,我们需要让LeavesViewController响应,跳到下一个Controller,其他场景视图。

LeavesViewController类为“半单例”:

LeavesViewController.h

#import<UIKit/UIKit.h>

#import"LeavesView.h"


@interface LeavesViewController :UIViewController <LeavesViewDataSource,LeavesViewDelegate

{

LeavesView *leavesView;

}

@property(nonatomic,retain)LeavesView *leavesView;


+ (id)shareInstance;


- (void)goToPlay;

@end


LeavesViewController.m

#import"LeavesViewController.h"

#import"ASCcLevelOnePaperScene.h"


staticLeavesViewController *leavesViewInstance = nil;


@implementation LeavesViewController


@synthesize leavesView;

- (id)init 

{

    if (self = [superinit]) 

    {

       leavesView = [[LeavesViewalloc] initWithFrame:CGRectZero];

       leavesView.mode =UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? LeavesViewModeSinglePage : LeavesViewModeFacingPages;

       leavesViewInstance = self;       //注意这里

    }

   return self;

}


- (void)dealloc 

{

    [leavesViewrelease];

   leavesViewInstance = nil;      //释放全局变量

    [superdealloc];

}


+ (id)shareInstance

{   

   //NSAssert(leavesViewInstance!=nil,@"leavesViewInstance can not be nil!");

   if(leavesViewInstance ==nil)

       leavesViewInstance = [selfinit];

   return leavesViewInstance;

}


这里只展示了“半单例”的实现部分,关于Controller都有的ViewDidLoad等方法和其他相关实现方法,这里与“半单例”无关,不做展示

LeavesView只是一个普通的视图类。

当LeavesView判断到最后一页时:

if([selfhasNextPage]==NO)

{

    NSLog(@"最后一页!");

    [[LeavesViewControllershareInstance] goToPlay];

}


[LeavesViewControllershareInstance]得到当前ViewController。再发送消息goToPlay,让ViewController响应。