自我毁灭单身devise模式iOS

我最近遇到了一个问题,我只想要一个特定对象的实例存在,只存在一个短暂的时间内执行特定的操作。 它的操作是asynchronous的,所以如果我没有引用它,ARC会在运行循环结束时将其解除分配。 如果我坚持下去,我会需要委托callback或通知来知道什么时候发布它。

该对象需要下载几个图像和其他数据并将其caching到磁盘。 我不希望它浪费内存,因为caching限制大约是24小时。 我也不需要任何反馈; 我希望它能够完成它的任务,并且自己完成。

我想出了一个我很喜欢的devise模式。 从那时起,我就在其他一些项目中使用过它,并且如果它是一个众所周知和分析的模式,我只是不知道(自毁单身)。 我想知道,所以我可以意识到我目前没有看到任何潜在的陷阱。

我也很感兴趣,听到你们可能有什么关于为什么这是一个糟糕的devise的input。

devise就像这样(这是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]; 

现在,如果需要的话,这个对象将会下载,并且在完成时释放它自己,或者根本不创build它自己。 它也不会去开始下载数据两次。

我知道这个devise在扩展性和function上有局限性,但是对于这样的一个实例,以及我用过的其他实例,我发现它非常有用。

这很常见的使用块。 考虑类似的东西(尽pipe我可能会以不同的方式处理多个调用…)

 void ExecuteWithMySingleSelfDestructingObject(void(^block)(MySelfDestructingClass *object)) { static MySelfDestructingClass* singleton; @synchronized(singleton) { if (singleton) { // To get past the synchronization primitive, this must be a recursive call. } // Whatever other conditions you want to have (like your date check) singleton = [[MySelfDestructingClass] alloc] init]; @try { block(singleton); } @finally { singleton = nil; } } } 

请注意双重exception处理(尝试/最后再加上什么@synchronized做 – 可能要改变…

然后做任何你想要的块…

 ExecuteWithMySingleSelfDestructingObject(^(MySelfDestructingClass *object){ // Do whatever I want with the singleton instance that has // been given to me as <object> }); 

当然,这可能是一个类的方法…

 + (void)performBlock:(void(^)(MySelfDestructingClass *object))block { static MySelfDestructingClass* singleton; @synchronized(singleton) { if (singleton) { // To get past the synchronization primitive, this must be a recursive call. } // Whatever other conditions you want to have (like your date check) singleton = [[self] alloc] init]; @try { block(singleton); } @finally { singleton = nil; } } } [MySelfDestructingClass performBlock:^(MySelfDestructingClass *object){ // Do whatever I want with the singleton instance that has // been given to me as <object> }]; 

我希望这是有道理的(我自由input,所以语法可能会有所不同,但你应该明白)。