2013-10-27 81 views
12

我仍然圍繞着RAC和FRP一般 - 我正在努力弄清楚如何實現我通常不得不在其他地方使用的模式。ReactiveCocoa中的緩存失效

比方說,我正在製作一個閃存卡應用程序,主屏幕是我的一副撲克牌列表。這個應用程序使用網絡服務器的狀態作爲事實的來源。我不想在每次顯示屏幕時從服務器重新獲取此列表 - 非常好,我可以在帶有重播主題的多播信號中使用延遲網絡請求,以有效地記錄該列表。

我有兩種方法,這個列表應該通過從服務器重新獲取來刷新,這對我來說變得複雜了。我希望能夠在應用程序中發生任何數量的事情時使這個「緩存」列表失效(例如,用戶導航到其他屏幕並執行某些操作,使主屏幕上的套牌列表過時,或者應用程序剛剛被重新喚醒,所以我們可以猜測它可能已經過時了),以便下一次用戶返回到主屏幕時,它將不會顯示任何內容(而不是顯示舊列表,因爲它知道它是由於用戶的行爲而過時),並且將重新獲取列表,在下載之後顯示它。我怎樣才能最優雅地處理這種「無效」狀態(希望沒有實際狀態)?

我也希望能夠在超時時間內將「緩存」列表過期 - 基本上,甲板列表信號會給出緩存列表直到足夠的時間過去,此時它會懶惰地發出網絡請求提供數據。

我對如何實現這兩件事有一些想法,但他們似乎有點複雜。希望得到一些指導或指向某個示例項目的方向。

我可以看到處理這個問題的一個簡單方法是有一個必要的服務層,並且必須處理緩存和緩存失效,並使用廣播事件來使緩存無效並從緩存返回或產生網絡請求到當反應層嘗試訪問數據時填充緩存。如果不先理解這種做法的被動方式,我寧願不遵循這種方法。

謝謝!

+0

跨張貼在這裏:https://github.com/ReactiveCocoa/ReactiveCocoa/issues/899 – aehlke

+1

我愛答案由@kastiglione在該帖子中發佈。 – erikprice

回答

11

答案從GitHub

答案複製可以去很多方面,安裝程序不會提供太多的限制。那樣,我會提出一些建議讓對話開始。

首先,看看+merge:,它允許您通過將其值彙集到單個信號中來組合一組信號。

RACSignal *deckInvalidated = [[RACSignal merge:@[ 
    userDidSomethingSignal, 
    appReawokenSignal, 
    // etc 
]]; 

有了到位,我們需要的是信號轉變成一個無論何時無效事件發生時,服務器會甲板。

在我們做到這一點之前,讓我們看看信號請求的樣子。假設您有一個RACified API客戶端。

RACSignal *fetchDecks = [[APIClient fetchDecks] startWith:nil]; 

使用-startWith:在這一點上是有點前瞻性的想法。該計劃將形成一個信號,該信號將使用宏「RAC」綁定到某個酒店,並且通過使用startWith:nil,每當有新的請求開始時,該屬性將設置爲nil。這是按照您的要求:

什麼都不顯示在第一(而不是顯示舊的名單,因爲它知道它是過時的,由於用戶的操作),並重新讀取列表

現在我們可以將失效事件映射到網絡請求中,它看起來很簡單,但它缺少一些東西。

RAC(self, decks) = [[deckInvalidated mapReplace:fetchDecks] switchToLatest]; 

這沒有任何清爽到期。爲了做到這一點,讓我們做出以下-repeat秒的適當-delay後,前面的請求完成的請求信號:

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]; 
+0

太棒了!這增加了很多清晰度,謝謝。夫婦的事情首先雖然:我希望甲板獲取懶惰發生,而不是一旦失效。它應該只需要一次(用於向用戶演示等),如果我理解正確,RAC(自我,甲板)就會渴望。 – aehlke

+0

如果這是懶惰的,那麼這個問題應該遠離同一資源同時啓動的多個請求。這將是一個問題,否則由於API調用不一定便宜。 – aehlke

+0

對於RAC的最佳實踐,我還有點困惑,或者更確切地說,副作用實際上應該發生。如果不需要它們,避免屬性是不是最好,並且使用回放主題?或者,回放主題與屬性一樣「不好」,因爲它只是另一種形式的狀態。 – aehlke