2017-05-05 57 views
0

當我從數據庫中刪除NSMangedObject時,分配給它的局部變量會發生什麼?存儲對已刪除引用的局部變量會發生什麼情況NSManagedObjects

例如,我有一個簡單的NSManagedObject:

class MyManagedObject: NSManagedObject { 
    @NSManaged var name: String 
} 

然後在我的ViewController,我拉出來的數據庫,並在本地指派方式:

class ViewController: UIViewController { 
    var myManagedObject: MyManagedObject! 
} 

然後我刪除它來自數據庫。

如果打印對象的名字,我在控制檯中

print("myManagedObject.name = \(myManagedObject.name)") 
//prints: "myManagedObject.name = " 

以下彷彿對象,不是嗎?但是如果我把變量變成可選的並且檢查它爲零,我被告知它不是零。

我不太清楚如何在腦海中調和這一點。似乎有東西指向局部變量,但其屬性已消失。

如果我有許多不同的UI對象依賴於該對象的屬性,我不能假設它在內存中有一些本地深層副本?


這裏比較完整的代碼:

在viewDidLoad中創建新的對象,保存上下文,獲取對象,然後將其指定本地。

class ViewController: UIViewController { 

     var myManagedObject: MyManagedObject! 

     override func viewDidLoad() { 
      super.viewDidLoad() 

      //1 Create the new object 
      let newObject = NSEntityDescription.insertNewObject(forEntityName: "MyManagedObject", into: coreDataManager.mainContext) as! MyManagedObject 
      newObject.name = "My First Managed Object" 

      //2 Save it into the context 
      do { 
       try coreDataManager.mainContext.save() 
      } catch { 
       //handle error 
      } 

      //3 Fetch it from the database 
      let request = NSFetchRequest<MyManagedObject>(entityName: "MyManagedObject") 
      do { 
       let saved = try coreDataManager.mainContext.fetch(request) 
       //4 Store it in a local variable 
       self.myManagedObject = saved.first 
      } catch { 
       //handle errors 
      } 
     } 
} 

在這一點上,如果我打印出局部變量的name財產,我得到正確的響應:

print("The object's name is: \(myManagedObject.name)") 
//prints: The object's name is: My First Managed Object 

所以,現在我從數據庫中刪除:

if let storedObject = myManagedObject { 
    coreDataManager.mainContext.delete(storedObject) 
    do { 
     try coreDataManager.mainContext.save() 
    } catch { 
     //handle error 
    } 
} 

但現在,當我打印時,我得到最奇怪的輸出:

print("myManagedObject.name = \(myManagedObject.name)") 
//prints: "myManagedObject.name = " 

這完全不是我期待記憶工作的方式。如果我創建類Foo的實例,然後將該實例傳遞給不同的對象,則它是相同的實例。一旦沒有人指出它,它就會消失。

在這種情況下---什麼是變量,myManagedObject?這不是nil。什麼是字符串,name?它是一個空字符串嗎?還是它是一些其他奇怪的元類型?

+0

顯示代碼,你「分配」在本地。 var myManagedObject:MyManagedObject!將只是「創造」一個類型爲MyManagedObject的新變量 – Retterdesdialogs

+0

由於您的問題更新:刪除託管對象後,您將其標記爲已刪除,保存數據庫後,將其從數據庫(不在內存中)中刪除。在託管對象上,您應該檢查isDeleted屬性或甚至「fault」屬性。該對象按照您的預測持續存在,但其行爲在您的情況下是不可預測的。任何事情都可能發生,取決於框架的變化,空字符串似乎是一個很好的解決方法,它仍然可以工作。刪除後不要使用這個對象是你的工作。 –

+0

但兔子洞更深。如果您使用多個上下文,並且您在一個上下文中刪除該對象,它仍然會存在於另一個上下文中。但是,一旦您嘗試在第二個環境中應用更改,就會報告您需要解決的衝突。因此,在內存中,每個上下文都有一個實例,這些實例將保存在內存中,直到ARC規則決定釋放它爲止。但其性能隨時可能發生變化。對象仍然存在但其屬性無法訪問。通過一切權利它應該崩潰,但它似乎是例外爲您處理。 –

回答

0

您可能在這裏尋找的主要內容是核心數據上下文。上下文是您的內存和實際數據庫之間的連接。

每當您獲取數據時,都會通過上下文獲取數據。這些是可以修改或甚至刪除的管理對象。在保存上下文之前,這些數據仍然不會發生在數據庫上。

當你刪除一個對象時,它被標記爲刪除,但它不會從內存中刪除,它不能被刪除,因爲如果沒有其他內容,它仍然會被上下文用來實際從數據庫本身刪除對象。

,一旦您調用刪除它幾乎是無關緊要的,即使證明它可能會改變,因爲它是框架的一部分發生了管理對象是什麼。因此,您有責任檢查這些案例並在需要時重新提取對象。因此,您必須確保您的應用程序具有適當的架構並負責任地使用核心數據。

有你如何使用您的數據庫和或多或少任何人有最佳使用它的一個獨特的方式很多種。您需要更具體地瞭解您正在做的事情以及您在哪裏看到潛在問題,以便我們能夠幫助您走上正確的道路。

給你舉個例子,考慮從遠程服務器數據同步。在這裏,您希望無論用戶在做什麼或者他是哪個應用程序的哪一部分,都可以隨時同步數據。

爲此,我建議你有一個單獨的線程運行一個單一的環境。所有的託管對象都應該被包裝,並且一旦從數據庫中檢索到它的屬性就會被複制。在大多數實體,你會碰到這樣的:

MyEntity.findAll { items in 
    ...the fetch happens on context thread and returns to main, items are wrappers 
} 
MyEntity.find(id: idString, { item in 
    ...the fetch happens on context thread and returns to main, items are wrappers 
})() 

然後因爲你沒有給管理對象的任何直接訪問您需要某種方法來將數據複製到被管理的對象,如:

myEntityInstance.commit() // Copies all the data to core data object. The operation is done on a context thread. A callback is usually not needed 

然後保存數據庫

MyEntity.saveDatabse { 
    ... save happens on the context thread and callback is called on main thread 
} 

現在的智能部分是saveDatabse方法是更改​​已經作出的委託報告。委託人通常是當前的視圖控制器,所以有一個超類,如DataBaseViewController,它看起來確實出現了分配自己作爲委託MyEntity.delegate = self,在視圖確實加載調用一些方法reloadData和在databaseDidChange委託方法調用reloadDataviewWillAppear相同。

現在每個視圖控制器是的DataBaseViewController子類覆蓋reloadData,並在該方法中,你將再次從數據庫讀取數據。要麼你正在獲取所有項目或一個。所以對於那些單一的人來說,你需要保存對象的id,並通過那個id再次獲取它。如果返回的對象是nil,那麼該項目已被刪除,以便捕獲您似乎提到的問題。

所有這些事情都過於簡單,但我希望你能對核心數據以及如何使用它的基本思想。這並不容易,它從來不是,也很可能永遠不會。它旨在使速度能夠在最短的時間內從一個非常大的數據庫訪問數據。其結果是它可能不是很安全。

+0

當你說:「所有的託管對象都應該被打包並且其屬性一旦從數據庫中檢索就被複制。」你是說當你使用CoreData時,一旦你從數據庫中檢索你的對象,你實際上將所有的屬性拷貝到內存中的新的非託管對象中?所以你需要爲你的所有類創建兩個版本:一個是託管的,一個是非託管的。 – MH175

+0

在我描述的是的情況下。但是對於複雜的案例來說,這不是你通常需要的東西。起初可能看起來很奇怪,但一旦你看到這些對象不僅僅是核心數據,而且還包括服務器數據(json字典)和可用於複雜系統(如MVVM)並且完全線程安全的UI模型,你可能會發現它很方便。如果你正在考慮創建這個系統,我建議你有一個完成大部分工作的超類,那麼子類只需要2種方法用於從管理對象轉換到管理對象。請注意,核心數據支持子類 –

相關問題