iOS 自毁单例设计模式

2024-04-02

我最近遇到一个问题,其中我只希望特定对象存在一个实例,并且仅存在执行特定操作所需的短暂时间。它的操作是异步的,因此如果我没有保存对它的引用,ARC 会在运行循环结束时释放它。如果我确实保留它,我将需要委托回调或通知来知道何时完成释放它。

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

我想出了一个我非常喜欢的设计模式。从那时起,我在其他几个项目中使用了它,并且很好奇它是否是一个我不知道的众所周知且经过分析的模式(自毁单例???)。我想知道,这样我就可以了解我目前没有看到的任何潜在陷阱。

我也很想听听你们对为什么这是一个糟糕的设计的任何意见。

设计是这样的(这是 ARC,但如果通过类方法释放单例,非 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];

现在,该对象将在需要时下载内容,并在完成后释放自身,或者根本不创建自身。它也不会开始两次下载数据。

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


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

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

注意双重异常处理(try/finally 加上 @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>
}];

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS 自毁单例设计模式 的相关文章

随机推荐

  • 关于“ls”,我如何只显示目录(链接目录和隐藏目录除外)

    我遇到一些关于 ls 这个命令的问题 我只想打印没有隐藏或链接的目录 但我用 man ls 查看解释 但没有找到 如果有一面旗帜表明我可以做我想做的事 thanks 下面是我要解决的问题 4 显示可见出口 This is two comma
  • 来自 Jenkins 的参考 Xcode 版本号

    我正在尝试在 Jenkins Build 中获取对 Xcode 项目 CFBundleVersionString 或 CFBundleVersion 的引用 我的目标是能够以这种方式设置内部版本号 CFBundleVersionString
  • Python 中 pickle 的常见用例

    我看过pickle http en wikipedia org wiki Pickle 28Python 29文档 但我不明白 pickle 在哪里有用 pickle 的一些常见用例有哪些 我遇到过的一些用途 1 将程序的状态数据保存到磁盘
  • 如何最大化和最小化div(没有jquery只有javascript)

    你好 我需要仅使用javascript而不是jquery来最大化或最小化我的html页面中的div 我希望能够这样做http jsfiddle net miqdad Qy6Sj 1 http jsfiddle net miqdad Qy6S
  • 如何在 winform 中托管带有 UI 的控制台 exe

    我正在开发一个具有某些特定要求的项目 我需要创建一个可以使用 C 监视并在其中运行 exe 的程序 然而 使用控制台程序来实际托管另一个exe的方法似乎没有尽头 所以我使用了WinForm 我一直在寻找并找到了一些非常好的解决方案 它在 W
  • 在PowerShell中获取PATH环境变量

    我想检查 PowerShell 中的 PATH 环境变量 我试过了 Get ChildItem env path 我想获得完整的路径 但只获得其中的很小一部分 我得到多少取决于 PowerShell 窗口的宽度 例如 C Program F
  • Google API 客户端机密错误 (Python)

    我想从 Google Analytics 检索数据 我已经在控制台中创建了一个服务帐户 并且我正在使用 Google 的 Python hello analytics api v3 py 代码来访问数据 我已经复制了client secre
  • Mac OS Cocoa:在画布上绘制一个简单的像素

    我希望我能找到这个问题的答案 我搜索了又搜索 找不到正确的答案 这是我的情况 在 Mac OS Cocoa 应用程序中 我想在应用程序窗口的专用区域上绘制一个像素 实际上是几个像素 我想 如果有一个就更好了NSImageView放置在那里
  • 对多列进行 GroupBy 并应用移动功能

    假设我有这个数据集 Country id Company id Date Company value 1 1 01 01 2018 1 1 1 02 01 2018 0 1 1 03 01 2018 2 1 1 04 01 2018 NA
  • 如何在jest和enzyme中设置useState Hook的初始状态?

    目前我正在使用带有反应钩子的功能组件 但我无法测试useState完全挂钩 考虑这样一个场景 useEffect钩子我正在执行 API 调用并在中设置值useState 对于笑话 酶 我模拟了要测试的数据 但我无法设置初始状态值useSta
  • 有没有一个工具可以检测重复的接口 GUID?

    这是一个典型的复制粘贴错误 如果复制粘贴某些包含带有 GUID 的接口声明的 Delphi 代码 Delphi 将不会抱怨并编译在不同位置重复使用相同 GUID 的代码 支持 功能基于 GUID 与接口配合使用 因此可能会出现错误 是否有可
  • dotNet(或 C#)中是否考虑了闰秒?

    DateTime 结构会处理这个问题吗 还有其他类 结构吗 更新 我现在读到闰秒只提前 6 个月宣布 因为地球的自转不是那么可预测的 由于在未来的日期中不可能实现这一点 我可以想象他们只是省略了它们 据我所知 NET 的 DateTime
  • 如何在瘦控制台窗口中查看调试代码?

    在 Mongrel 中 我们能够看到任何 ruby 调试代码 安装 Thin 并执行后thin start 我在控制台窗口上没有看到任何调试代码 这是正常的吗 我们应该使用tail f log development log在新的控制台窗口
  • 如何指定Qmake自动生成的资源文件?

    我有一个带有德语翻译的 Qt 项目 Translation de ts 自动编译成Translation de qm通过 Qmake TRANSLATIONS Translation de ts QMAKE EXTRA COMPILERS
  • Fluent-NHibernate 是否支持映射到过程?

    我一直想知道是否可以让 Fluent NHibernate 与已经存在的存储过程进行通信 并将结果集的映射分配给我自己的域对象 Fluent NHibernate 是否能够直接执行不返回结果集的过程 基本上 我一直在考虑使用 Fluent
  • Math.cos() 给出错误结果

    根据 Wolfram Mathematica 的说法 cos 50 0 6427876096865394 但是 Java 中的这段代码 System out println Math cos 50 gives 0 9649660284921
  • SongsController#index 中的 NameError 未初始化常量 Song::FriendlyId

    所以 我有一个应用程序 用户可以在其中进行大量的社交分享 因此 链接必须看起来很漂亮 我已经安装了友好 ID 宝石 http rubydoc info github norman friendly id master 但似乎收到此错误 Na
  • SQL Server:为第 1 列中的每个唯一值插入一个新行

    使用 SQL Server 我尝试查找表的第 1 列中的每个唯一值 然后使用该唯一的第 1 列值插入新行并添加第 2 列值 第 2 列的值每次都相同 需要注意的是 我可以通过从第 1 列的数据库中提取唯一值并为每个值添加一个插入来完成此操作
  • Delphi XE4 iOS 应用程序可以在模拟器上运行,但不能在调试设备上运行

    我让应用程序在加载应用程序时显示其指定的背景图像 然后在启动时运行此代码会崩溃 unzip own resources like images data files ettc FAppDataDirPath GetHomePath Path
  • iOS 自毁单例设计模式

    我最近遇到一个问题 其中我只希望特定对象存在一个实例 并且仅存在执行特定操作所需的短暂时间 它的操作是异步的 因此如果我没有保存对它的引用 ARC 会在运行循环结束时释放它 如果我确实保留它 我将需要委托回调或通知来知道何时完成释放它 该对