2015-09-16 36 views
1

我有一個應用程序使用parse將數據存儲在parse的本地數據存儲中,並將所述數據備份到解析雲。一般來說,這是非常好的。代碼存儲在本地和雲數據的關鍵位如下:快速終止應用程序時解析saveEventually失敗

- (void)store:(PFObject*) parseObject { 
    if (parseObject) { 
     [parseObject pinInBackground]; 
     [parseObject saveEventually]; 
    } else 
     NSLog(@"Err :Store was passed a nil?"); 
} 

我有一個應用程序,其中一些網友紛紛表示,有數據損失,如果他們建立自己的數據,然後終止應用程序「不久, '之後。

當用戶數據更新時,函數傳遞10個或更多項以快速連續存儲。

我已通過執行以下操作測試了此場景。我讓所有的項目都被存儲起來,並設置一個斷點來完成這個任務。然後我讓應用程序再次運行並通過按主頁鍵並將應用程序劃掉來終止它。它還有一段左右的運行時間,但關鍵點在於任何情況下,商店都已完成每個對象。

我確實發現數據可能會丟失。看起來,只是因爲這些方法已經運行並不能保證數據將被存儲。爲了清楚起見,我明白這些函數不會存儲數據,但我曾想過(假設)存儲數據的意圖在完成後有保證。

我想補充以下內容:

  1. 後來的數據丟失更敏感。即看起來解析對數據順序地進行處理。
  2. 您可以發現數據固定在本地數據存儲中,但不會解析(幾乎可以像引腳一樣工作,但最終不會保存)。
  3. 較舊的(較慢的?)設備比較新的設備更易受影響。事實上,我努力在新的iPad mini上實現它,但可以在iPhone 4上實現。
  4. 需要啓用網絡,但是如果模擬壞的網絡會更容易(使用iOS設置裝置)。
  5. 數據量很小(100s字節),我沒有達到解析保存限制。
  6. 我正在使用Parse 1.8.4版。

我的問題如下:

我期待,一旦這些調用已返回任務是鎖着的離去,總是完成。我明白,無法保證最終保存多久,但即使在下次運行應用程序時,它總是會「最終」完成。我做錯了什麼?我是否遇到過這種類型的數據丟失,需要採取進一步的預防措施?有沒有人有任何經驗或建議?即使只是你覺得它適合你?可能是因爲我在其他地方做了一些愚蠢的事情,但很難看出如何。

謝謝你的時間。

+0

如果你在殺死它之後再次啓動應用程序,數據是否最終被髮送到Parse?保存最終會完成它所說的內容,它最終會保存,而不是您稱之爲的分割秒。如果您在網絡連接完成之前終止應用程序,則會在下次應用程序運行時嘗試保存。 –

+0

不,數據不會解析,無論您重新啓動應用後等待多久。數據丟失。就像我的用戶一樣,這就像任務沒有按計劃進行。不在本地數據存儲區或雲中(我可以通過解析門戶網站查看數據,看不到它)。 – pyrrhoofcam

+0

我懷疑它可能是pinInBackground沒有完成,但是如果你強迫退出一個應用程序,你必須期望壞事會發生。如果用戶終止應用程序,即使是同步通話可能也無濟於事,它們實際上會在應用程序中途停止。 – Paulw11

回答

3

我在這裏發佈我自己的結果,也許他們會對某人有用。這是我對Parse源碼進行回顧後的工作原理的理解,我不能保證這是最終的文字或整個故事,但它符合事實。

解析現在是開源的,所以你至少可以去看看如果你有問題來確定發生了什麼。

Parse in github

解析保持的任務隊列,他們是嚴格按照它們被請求的順序進行處理。無論任務是在前臺(阻塞)還是在後臺請求(有或沒有回調),都是如此。此外,如果任務是查詢,引腳,保存等等,它們都排在任務列表中並不重要。任務列表保存在內存中,如果應用程序被暫停然後終止或在所有任務處理完成之前終止任務丟失。所以,如果解析沒有做任何事情,並且你要求一個pin或一個保存,它就會開始這個,很可能一切都會好起來的。

如果解析是忙碌的(按照我上面的描述),您的saveEventually在隊列末尾等待處理。在處理此任務之前,您有可能無法通過Parse記錄saveEventually。請注意,理解這一點非常重要,我的意思是看看任務 - 不完成任務 - 只是簡單地看看任務是什麼,並在saveEventually情況下記錄它。

我不一定認爲這是一個錯誤。我的問題是我正在查看saveEventually作爲數據庫提交。我知道這並不意味着它還在雲端,我只是推測,將它推送到雲端的請求在saveEventually返回時以非易失性方式存儲。一旦它被處理,它就像一個提交,它會最終到達雲端,但是你不能確定它已被編程處理(saveEventually回調完成時不記錄saveEventually)。

如果該應用程序被nuked那麼這樣做,用戶採取了一些行動,他們應該知道他們在做什麼。但是,如果您聲明您的應用程序有後臺任務,那麼您可以確保在用戶按下主鍵或移動到另一個應用程序時仍然有一個線程執行 - 我認爲他們有權執行此操作。我已經這樣做了,似乎可以防止我看到的數據丟失。我基本上確保處理任務列表,並且Parse已經記下了我所有的saveEventuallys,即使應用程序轉到了後臺。

iOS Background Execution

這是很難確定何時終止該線程。在我的應用程序中,我做了一個別針,並且成對保存了最終成果。該引腳確實有回調,所以我保持優秀的引腳數。當它達到零時,我等待一分鐘並關閉線程。這給了1分鐘來執行最終的saveEventually,這在測試中看起來已經足夠了。如果我在那時可以訪問互聯網,那麼保存最後的或下次運行的應用程序都會記錄下來。

我認爲你必須是相當沉重的Parse用戶才能看到這個問題。我有許多小數據對象分佈在不相關的不同表上。這會創建大量的查詢和備份引腳,如果您有一個表格或一個數據blob,您可以一次插入,則不會看到我描述的問題。

示例代碼(7Jan16編輯),按照註解請求

下面是我使用實現上述代碼的核心。如果你使用它,你將需要改變它。我建議閱讀上面的背景任務鏈接。後臺線程使應用程序保持活躍狀態​​,解析仍然可以處理其未完成的任務。

此代碼塊的意圖是提供一個輔助函數來跟蹤所有未解析的請求進行解析。它在調用時啓動後臺線程(startPinMonitor)。只有一個監視器被啓動,這在startPinMonitor中被檢查。我的代碼在UI線程上運行,否則在這裏可能需要一些同步邏輯。

- (void)store:(PFObject*) parseObject { 
    if (parseObject) { 
     if (self.outStandingPins == 0) 
      [self startPinMonitor]; 

     self.outStandingPins++; 

     [parseObject pinInBackgroundWithBlock:^(BOOL succeeded, NSError *error) { 
      self.outStandingPins--; 
      if(!succeeded) 
       NSLog(@"Err : Pin failed?"); 
     }]; 

     [parseObject saveEventually]; 
    } 
} 

這段代碼的意圖是保持應用程序運行,直到處理完所有剩餘的分析操作。它首先檢查監視器是否已經激活。 'checkPinStatus'方法每30秒調用一次,並在所有引腳都被處理時終止。突出引腳的日誌對檢測正確的操作非常有用。按Home鍵後,您應該能夠驗證應用程序仍在運行。如果您註釋掉'beginBackgroundTaskWithExpirationHandler'方法,您可以確定此代碼試圖實現的行爲差異。

-(void) startPinMonitor { 
    if (![self.myTimer isValid]) { 
     self.myTimer = [NSTimer scheduledTimerWithTimeInterval:30 
                 target:self 
            selector:@selector(checkPinStatus) 
                 userInfo:nil 
                 repeats:YES]; 

     self.myBackgroundTask = [[UIApplication sharedApplication] 
         beginBackgroundTaskWithExpirationHandler:^{ 
          NSLog(@"Background tasks stopped"); 
         }]; 
    } 
} 

-(void) checkPinStatus { 
    NSLog(@"Current outStandingPins=%i", self.outStandingPins); 

    if (self.outStandingPins == 0) { 
     [self.myTimer invalidate]; 
     [[UIApplication sharedApplication] 
      endBackgroundTask:self.myBackgroundTask]; 
    } 
} 
+0

pyrrhoofcam,很棒的信息。你能否詳細說明你是如何完成這部分的? 「但是,如果你聲明你的應用程序有後臺任務,那麼你可以確保在用戶按下主鍵或移動到另一個應用程序時仍然有一個線程可執行 - 我認爲他們有權這麼做。這似乎可以防止我看到的數據丟失,我基本上確保處理任務列表,並且Parse已經記下了我所有的saveEventually,即使應用程序轉到了後臺。 – adrian1kat