我最近遇到了一个问题,我只希望特定对象的一个实例存在,并且只存在执行特定操作所需的短暂时间。它的操作是异步的,所以如果我没有对它的引用,ARC 会在运行循环结束时释放它。如果我确实坚持它,我将需要委托回调或通知来知道何时完成释放它。
该对象需要下载多个图像和其他数据并将其缓存到磁盘。我不希望它在不缓存项目时浪费内存,因为缓存限制约为 24 小时。我也不需要任何形式的反馈。我希望它执行它的任务并自己完成。
我想出了一个我非常喜欢的设计模式。从那以后,我在其他几个项目中使用了它,如果它是一种我不知道的众所周知和分析过的模式(自毁单例???),那我就很好奇了。我想知道,这样我就可以知道我目前没有看到的任何潜在陷阱。
我也很想听听你们关于为什么这是一个糟糕的设计的任何意见。
设计是这样的(这是 ARC,但如果您通过类方法释放单例,非弧也可以工作):
一个全局静态对象(不是真正的单例,因为它不会一直存在)
static MySelfDestructingClass* singleton;
单个公共类方法
+ (void)downloadAndCacheDataIfNeeded
{
//Force synchronized access
@synchronized(singleton){
//We are already doing something, return
if(singleton){
return;
}
NSDate* lastCacheDate = [[NSUserDefaults standardDefaults] objectForKey:kKeyForLastUpdate];
if([[NSDate date] timeIntervalSinceDate:lastCacheDate] > kCacheLimit){
//Our cache is out of date, we need to update
singleton = [[self alloc] init];
[singleton downloadAndCache];
}
}
}
现在我们的实例方法,我们需要我们的对象活着,以便请求可以回来:
- (void)downloadAndCache
{
//This would probably be a delegate, but for simplicity of this example it's a notification
[[NSNotificationCenter defaultCenter] addObserver:self forNotificationWithName:NotificationSomeRequestDidSucceed selector:@selector(someCustomRequestDidSucceed:withData:) object:nil];
[SomeCustomRequest makeRequestWithURL:@"http://www.someURL.com"];
}
- (void)someCustomRequestDidSucceed:(SomeCustomRequest *)request withData:(NSDictionary *)dictionary
{
//Do whatever we need to in order to save our data, or fire off image download requests etc...
....
//Set our lastUpdated time in NSUserDefaults
[[NSUserDefaults standardDefaults] setObject:[NSDate date] forKey:kKeyForLastUpdate];
//Remove our observer
[NSNotificationCenter defaultCenter] removeObserver:self name:NotificationSomeRequestDidSucceed object:nil];
//Release ourselves (ok not really, but tell arc we can be released)
singleton = nil;
}
这样,我在应用程序的其他任何地方都需要做的是:
[MySelfDestructingClass downloadAndCacheDataIfNeeded];
现在这个对象会在需要时下载东西并在完成后释放自己,或者根本不创建自己。它也不会开始下载数据两次。
我知道这种设计在可扩展性和功能方面存在局限性,但是对于像这样的实例以及我使用过的其他实例,我发现它非常有用。