2017-08-12 21 views
0

比方說,我們有一個核心數據實體Image,其中有一個屬性url存儲文件系統的URL到實際的圖像文件。我們可以實現刪除功能是這樣的:原子刪除數據庫實體和文件

func deleteImage(_ image: Image) { 
    do { 
     let url = image.url 
     delete(image) 
     try save() 
     try FileManager.default.removeItem(at: url) 
    } catch { 
     rollback() 
    } 
} 
  • 如果同時save()removeItem(at:)的成功,操作成功。
  • 如果save()失敗,數據庫將回滾到其原始狀態。
  • 但是,如果save()成功,但removeItem(at:)失敗,孤立文件將留在文件系統中。

有沒有一種方法,使deleteImage()原子,而不涉及一個單獨的進程檢查,並定期刪除孤立文件?

-

它可以使用isDeletableFile(atPath:),但仍然不是100%可靠。

func isDeletableFile(atPath path: String) -> Bool

試圖基於所述文件系統或文件系統中的特定文件的當前狀態的謂詞行爲不推薦。這樣做會造成奇怪的行爲或競賽狀況。嘗試一個操作(例如加載文件或創建目錄),檢查錯誤並妥善處理這些錯誤要比試圖提前弄清操作是否成功要好得多。

+0

爲什麼在刪除之前要保存一些東西?無論如何,你可以使用「guard」作爲save(): guard try save()else { throw throw throw here 然後嘗試刪除一個圖像 – Woof

+0

核心數據需要你調用save()實際上從數據庫中刪除實體。另外使用'guard'也不利於情況3。 –

回答

0

一個真正的原子刪除是很難實現的,但可以大大地提高了代碼的穩定性,如果你改變了語句的順序一點點:

  1. 刪除圖像數據庫。
  2. 如果成功,將文件移動到臨時文件夾。
  3. 如果成功,提交。
  4. 成功時刪除臨時文件夾中的文件,否則將文件移回原始位置。

如果操作1或2不成功,則回滾。 4的第一部分並不是真的必要,你可以或應該在某些點清理臨時文件夾(例如程序啓動,從後臺返回)。 4的其他部分可能會在一些導致狀態不一致的罕見情況下失敗。

更復雜的更改可能會導致原子刪除。您不會刪除您的對象,但只會將它們標記爲已刪除。第二步首先刪除文件(如果存在的話)和實體。您可以在每次刪除後立即應用此第二步,並在其他某些位置應用。這種解決方案的缺點是複雜性,因爲每次訪問數據時都必須考慮已刪除的對象。