Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c ReactiveCocoa中的缓存无效_Objective C_Design Patterns_Caching_Frp_Reactive Cocoa - Fatal编程技术网

Objective c ReactiveCocoa中的缓存无效

Objective c ReactiveCocoa中的缓存无效,objective-c,design-patterns,caching,frp,reactive-cocoa,Objective C,Design Patterns,Caching,Frp,Reactive Cocoa,总的来说,我仍在绞尽脑汁研究RAC和FRP——目前正努力找出如何实现我在其他地方经常使用的模式 假设我正在制作一个flashcard应用程序,主屏幕是我的卡片组列表。此应用程序使用网络服务器的状态作为真相来源。我不想每次显示屏幕时都从服务器上重新获取这个组列表——太棒了,我可以在多播信号中使用延迟的网络请求和重播主题来有效地记忆该列表 我有两种方法可以通过从服务器重新获取来刷新此列表,这对我来说很复杂。我希望能够在应用程序中发生任何事件时使此“缓存”列表无效(例如,用户导航到其他屏幕并执行某些操

总的来说,我仍在绞尽脑汁研究RAC和FRP——目前正努力找出如何实现我在其他地方经常使用的模式

假设我正在制作一个flashcard应用程序,主屏幕是我的卡片组列表。此应用程序使用网络服务器的状态作为真相来源。我不想每次显示屏幕时都从服务器上重新获取这个组列表——太棒了,我可以在多播信号中使用延迟的网络请求和重播主题来有效地记忆该列表

我有两种方法可以通过从服务器重新获取来刷新此列表,这对我来说很复杂。我希望能够在应用程序中发生任何事件时使此“缓存”列表无效(例如,用户导航到其他屏幕并执行某些操作,可能会使主屏幕上的甲板列表过期,或者应用程序刚刚被重新唤醒,因此我们可以猜测它可能已过期以确保安全),因此,当用户下次返回此主屏幕时,它将首先不显示任何内容(而不是显示旧列表,因为它知道由于用户的操作它已过期),并将重新获取列表,在下载后显示它。我如何才能最优雅地处理这个“无效”状态(希望没有实际状态)

我还希望能够在超时时使“cached”列表过期-基本上,deck list信号将给出缓存列表,直到足够的时间过去,此时它将在提供数据之前惰性地发出网络请求

我对如何实现这两件事有一些想法,但它们似乎有点复杂。希望能得到一些指导或被指向某个示例项目的方向

我可以看到一种简单的方法来处理这个问题,那就是有一个必须的服务层,必须处理缓存和缓存失效,并使用广播事件使缓存失效,或者从缓存返回,或者在反应层尝试访问数据时生成一个网络请求来填充缓存。我不想在不首先了解被动方式的情况下就采用这种方法

谢谢

从GitHub复制的答案

答案可能有很多方面,设置没有提供太多限制。因此,我将提出一些建议来开始对话

首先,看一看
+merge:
,它允许您通过将信号的值“漏斗式”组合成单个信号来组合信号集合

RACSignal *deckInvalidated = [[RACSignal merge:@[
    userDidSomethingSignal,
    appReawokenSignal,
    // etc
]];
有了它,我们需要将该信号转换为每当发生失效事件时从服务器获取数据组的信号

在此之前,让我们先看看信号请求是什么样子的。让我们假设您有一个racifiedapi客户端

RACSignal *fetchDecks = [[APIClient fetchDecks] startWith:nil];
在这一点上,使用
-startWith:
有点前瞻性。计划是使用
RAC
宏形成一个将“绑定”到属性的信号,并通过使用
startWith:nil
,每当新请求开始时,该属性将被设置为
nil
。这是为了满足您的要求:

首先不显示任何内容(而不是显示旧列表,因为它知道由于用户的操作,它已过期),并将重新获取列表

现在我们可以将失效事件映射到网络请求中,这看起来很简单,但它缺少一些东西

RAC(self, decks) = [[deckInvalidated mapReplace:fetchDecks] switchToLatest];
这缺少任何有效期。为了做到这一点,让我们发出一个请求信号,在完成前一个请求后,在适当的
-延迟后,重复
s:

RACSignal *delay = [[RACSignal empty] delay:AEDeckRefreshTimeout];

RACSignal *repeatingFetchDecks = [[fetchDecks concat:delay] repeat];
现在,重新查看
RAC
分配,只需稍微修改一下:

RAC(self, decks) = [[deckInvalidated mapReplace:repeatingFetchDecks] switchToLatest];
这仍然存在一个问题,失效事件可能会导致对服务器的并发请求。你没有提到这是一个问题,所以不确定这是否对你的应用程序用例是必要的/重要的,但还是要考虑的。

对于完整的概述,代码可以在单个信号合成中完成:

RAC(self, decks) = [[[RACSignal
    merge:@[
        userDidSomethingSignal,
        appReawokenSignal,
    ]]
    mapReplace:[[[[APIClient
        fetchDecks]
        startWith:nil]
        concat:[[RACSignal
            empty]
            delay:AEDeckRefreshTimeout]]
        repeat]]
    switchToLatest];

交叉贴在这里:我喜欢@kastiglione在该帖中发布的答案。太棒了!这增加了很多清晰度,谢谢。不过,首先要做两件事:我希望套牌抓取可以懒散地进行,而不是在它失效后立即进行。如果我理解正确的话,RAC(self,decks)应该只需要一次(用于向用户演示等),并使其变得急切。如果这是懒惰的,那么问题应该消失,因为对于同一资源,多个请求同时被启动。否则这将是一个问题,因为API调用并不一定便宜。我还对RAC的最佳实践有点困惑,或者更确切地说,副作用应该发生在哪里。如果不需要属性,是否最好避免使用它们,而是使用播放主题?或者播放主题和属性一样“糟糕”,因为它只是另一种形式的状态。