自毁单身设计模式iOS [英] Self destructing singleton design pattern iOS

查看:169
本文介绍了自毁单身设计模式iOS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近遇到一个问题,我只想要一个特定对象的一个​​实例存在,只存在执行特定操作所需的短暂时间。它的操作是异步的,所以如果我没有引用它,ARC将在运行循环的末尾释放它。如果我挂了它,我将需要委托回调或通知来知道何时完成释放它。



该对象需要下载多个图像和其他数据并将其缓存到磁盘。缓存限制大约在24小时之内,因为没有缓存项目,我不想浪费内存。我也不需要任何反馈;我想要它执行它的任务,并自己完成。



我想出了一个非常喜欢的设计模式。从那以后,我已经在其他几个项目中使用过它,如果它是一个众所周知的分析模式,我只是不知道(自毁单子)我想知道,所以我可以意识到我目前没有看到的任何潜在的陷阱。



我也很有兴趣听到你们为什么会是一个糟糕的设计的任何输入。



设计像这样(这是ARC,但是如果您通过类方法释放单例,则非弧也可以工作):



全局静态对象不是真的是一个单身,因为它不会在整个时间内生活)

  static MySelfDestructingClass * singleton; 

单一的公共类方法

  +(void)downloadAndCacheDataIfNeeded 
{
//强制同步访问
@synchronized(singleton){
//我们已经在做某事,返回
if(singleton){
return;
}
NSDate * lastCacheDate = [[NSUserDefaults standardDefaults] objectForKey:kKeyForLastUpdate];
if([[NSDate date] timeIntervalSinceDate:lastCacheDate]> kCacheLimit){
//我们的缓存已经过期,我们需要更新
singleton = [[self alloc] init] ;
[singleton downloadAndCache];
}
}
}

现在我们的实例方法需要我们的对象活着,所以请求可以回来:

   - (void)downloadAndCache 
{
/ /这可能是一个委托,但是为了简化这个例子,它是一个通知
[[NSNotificationCenter defaultCenter] addObserver:self forNotificationWithName:NotificationSomeRequestDidSucceed selector:@selector(someCustomRequestDidSucceed:withData :) object:nil];
[SomeCustomRequest makeRequestWithURL:@http://www.someURL.com];

}

- (void)someCustomRequestDidSucceed:(SomeCustomRequest *)请求withData:(NSDictionary *)字典
{

//做任何我们需要的,以保存我们的数据,或者消除图像下载请求等...
....


//在NSUserDefaults中设置我们的lastUpdated时间
[[NSUserDefaults standardDefaults] setObject:[NSDate date] forKey:kKeyForLastUpdate];

//删除我们的观察者
[NSNotificationCenter defaultCenter] removeObserver:self name:NotificationSomeRequestDidSucceed object:nil];

//释放自己(确定不是真的,但告诉弧我们可以被释放)
singleton = nil;
}

这样我应该在其他任何地方做的应用程序是: p>

  [MySelfDestructingClass downloadAndCacheDataIfNeeded]; 

现在这个对象将下载的东西,如果它需要并释放自己完成,或不创建自己在所有它也不会去开始下载数据两次。



我知道这种设计在扩展性和功能方面有局限性,但是对于这样一个实例,其他我使用它,我发现它非常有用。

解决方案

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

  void ExecuteWithMySingleSelfDestructingObject(void(^ block)(MySelfDestructingClass * object)){
static MySelfDestructingClass * singleton;
@synchronized(singleton){
if(singleton){
//要超越同步原语,这必须是递归调用。
}
//无论你想要什么其他条件(如你的日期检查)
singleton = [[MySelfDestructingClass] alloc] init];
@try {block(singleton); }
@finally {singleton = nil; }
}
}

注意双异常处理(try / finally plus what @synchronized确实 - 可能想要改变...



然后用块来做任何你想要的...

  ExecuteWithMySingleSelfDestructingObject(^(MySelfDestructingClass * object){
//做任何我想要的单例实例,
//作为<对象>
});

当然可以是一个类方法

  +(void)performBlock:(void(^)(MySelfDestructingClass * object))block {
static MySelfDestructingClass * singleton;
@synchronized(singleton){
if(singleton){
//要超越同步原语,这必须是一个递归调用
}
//无论你想要什么其他条件(如你的日期检查)
singleton = [[self] alloc] init];
@try {block leton); }
@finally {singleton = nil; }
}
}

[MySelfDestructingClass performBlock:^(MySelfDestructingClass * object){
//使用
的单例实例, //被赋予了< object>
}];

我希望这是有道理的(我自由键入,所以语法可能会有所不同,但你应该得到想法)。


I recently came across an issue in which I only wanted one instance of a particular object to exist, and exist for only the brief period of time it needed to perform a specific operation. Its operation was asynchronous so ARC would dealloc it at the end of the run loop if I didn't hold a reference to it. If I did hang onto it I would need delegate callbacks or notifications to know when it was done to release it.

The object needed to download several images and other data and cache it to disk. I didn't want it to waste memory when it wasn't caching items since the cache limit was around 24 hours. I also didn't need feedback of any kind from it; I wanted it to perform it's task and be done with itself.

I came up with a design pattern I liked quite nicely. I've used it in a few other projects since then, and was curios if it was a well known and analyzed pattern that I'm just not aware of (self-destructing singleton???). I'd like to know so I can be made aware of any potential pitfalls I'm not currently seeing.

I'm also very interested to hear any input you guys might have about why this is a bad design.

The Design Goes Like This (this is ARC, but non-arc can work too if you release the singleton through a class method):

A global static object (not really a singleton because it doesn't live the entire time)

    static MySelfDestructingClass* singleton;

A single public class method

    + (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];
             }
        }
     }

Now our instance methods, we need our object alive so the request can come back:

      - (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;
        } 

This way all I have to do anywhere else in the application is:

     [MySelfDestructingClass downloadAndCacheDataIfNeeded];

Now this object will download things if it needs to and release itself when it's done, or not create itself at all. It also won't go and start downloading the data twice.

I'm aware this design has limitations with extendibility and functionality, but for an instance like this, and the other ones I've used it for, I've found it quite useful.

解决方案

This pretty common using blocks. Consider something similar (though I would probably handle multiple invocations differently...)

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; }
    }
}

Note double exception handling (try/finally plus what @synchronized does - may want to change that...

Then do whatever you want with the block...

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

Of course, it could be a class method...

+ (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>
}];

I hope that makes sense (I typed it free-hand, so syntax may vary, but you should get the idea).

这篇关于自毁单身设计模式iOS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆