单例模式

单例模式确保为一个确定的类只有一个实例存在,而且有一个全局的访问指针只想它,他经常使用延时加载去在第一次使用的时候创建一个简单的实例。

           小贴士:苹果使用这个方法很频繁。比如:[NSUserDefaults standarUserDefaults], [UIApplicationsharedApplication],[UIScreen mainScreen],[NSFileManager defaultManager],都返回一个单例。

你可能会以为为什么你会介意一个类周围会有不止一个实例,代码和内存都很简化,对不对?

有一些情况下一个类只有一个实例会很有意义。比如:没有必要去有很多的Logger实例,除非你想要同时写入几个日记文件,或者,拥有一个全聚德配置控制的类,很容易就实现一个线程安全的单个共享资源,比如配置文件,而不是多个类同时修改同一个配置文件。

如何使用单例

看一下右边的这个图表:

它显示了一个Logger类只有一个属性,(也是一个实例),和两个方法init和sharedInstance;

第一次客户端发送sharedInstance消息,这和属性的实例还没有初始化,所以你要创建这个类的一个新的实例然后返回一个指针指向它。

下一次你调用sharedInstance方法,实例就会立马返回而不需要任何的初始化,这个逻辑保证任何时候都只有一个实例存在。

你将要实现这和模式通过创建一个单例的类去管理所有的album 数据。

你将会意识到在这个组中有一个叫做API的租在这个工程中,这是你将会将所有的提供给你的app服务的类放到其中。在这个组中创建一个叫做LibraryAPI的类,继承于NSObject。

打开LibraryAPI.h,加入以下方法:


  1. +(LibraryAPI*)sharedInstance;  



在LibraryAPI.m中加入这些方法:

+(LibraryAPI*) sharedInstance{  
   
//1  
   
staticLibraryAPI* _sharedInstance;  
   
//2  
   
staticdispatch_once_t once;  
   
//3  
   
   dispatch_once(&once,^{  
   
       _sharedInstance = [[LibraryAPI alloc]init];  
   
   });  
   
    
   return _sharedInstance;  
   
}

这个简单的方法中有很多内容:

1.    定义了一个静态变量去hold住类中的实例,确保它是全局可用的在你的类中。

2.    定义了一个静态变量dispatch_once_t类型的去确保这个初始化代码只执行一次。

3.    使用Grand Central Dispatch(GCD)去执行一个初始化LibraryAPI的实例的block,这就是单例设计模式的本质:这个初始化永远不会再次被调用一旦这个类被实例化。

下次你调用sharedInstance方法是,这个dispatch_once里面的block代码不会被执行了,你会得到一个先前创建这个LibraryAPI的一个引用。

现在你有了一个单例对象作为albums的入口指针,更进一步去创建一个类去处理库中数据的持久化。

在API组中创建一个PersistencyManager的继承于NSObject的类。打开它的.h文件,加入

#import “Album.h”再加入以下代码:

- (NSArray *)getAlbums;  
- (void)addAlbum:(Album *)album atIndex:(int)index;  
- (void)deleteAlbumAtIndex:(int)index;



以上是加入了三个方法去处理数据的。

打开.m文件在 @implemetation的上方加入这些代码:

@interface PersistencyManager () {  
   
   // an array of all albums  
   
   NSMutableArray *albums;  
   
}



上面的代码添加了一个类扩展,这是另一个添加私有变量和方法带类中所以外部的类并不只带他们,在这里,你声明了一个可变数组去hold住album的数据,这个数据是可变的以便你可以轻松地添加和删除专辑。

现在添加下面代码到PersistencyManager.m中去

- (id)init  
{  
    self = [super init];  
    if (self) {  
        albums = [NSMutableArray arrayWithArray:@[[[Album alloc] initWithTitle:@"Best of Bowie" artist:@"David Bowie" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_david%20bowie_best%20of%20bowie.png" year:@"1992"],  
                                           [[Album alloc] initWithTitle:@"It's My Life" artist:@"No Doubt" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_no%20doubt_its%20my%20life%20%20bathwater.png" year:@"2003"],  
                                           [[Album alloc] initWithTitle:@"Nothing Like The Sun" artist:@"Sting" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_sting_nothing%20like%20the%20sun.png" year:@"1999"],  
                                           [[Album alloc] initWithTitle:@"Staring at the Sun" artist:@"U2" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_u2_staring%20at%20the%20sun.png" year:@"2000"],  
                                           [[Album alloc] initWithTitle:@"American Pie" artist:@"Madonna" coverUrl:@"http://www.coversproject.com/static/thumbs/album/album_madonna_american%20pie.png" year:@"2000"]]];  
    
    }  
       
    return self;  
}  
-(NSArray *)getAlbums  
{  
    return albums;  
}  
   
-(void)addAlbum:(Album *)album atIndex:(int)index  
{  
    if (index < [albums count]) {  
        [albums insertObject:album atIndex:index];  
    }else{  
        [albums addObject:album];  
    }  
}  
   
- (void)deleteAlbumAtIndex:(int)index  
{  
    [albums removeObjectAtIndex:index];  
}

在init这个初始化函数中你用五个实例转会填充了这个数组,其他几个方法允许你去得到,添加额删除albums。编译你的工程确保仍能正确编译。

在这个时候你可能会疑问为什么PersistenceManager不是单例,它和LibraryAPI的关系会下下一部分的外观(Faade)设计模式中见到。