2016-07-15 12 views
2

次の例の関連オブジェクトが、ソース/ホストオブジェクトの割り当てが解除されたときに自動的に割り当てが解除されない理由を説明できます。以下のこのコード例は、を工夫して(前もって申し訳ありません)ですが、私の問題を説明しています。NSManagedObjectContextの割り当て解除の問題 - (Swift | Associated Objects)

import UIKit 
import CoreData 

class ViewController: UIViewController { 

    @IBAction func createProduct(sender: AnyObject) { 

     let context = CoreDataHelpers.vendBackgroundWorkerContext() 
     let newProduct = CoreDataHelpers.newProduct(context: context) 

     newProduct.sku = "8-084220001" 

     do { 
      try newProduct.managedObjectContext?.save() 
      print("Product created [SKU: \(newProduct.sku ?? "NotDefined")]") 
     } catch { 
      print(error) 
     } 
    } 
} 


public class CoreDataHelpers { 

    public static let mainContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext 

    public class func vendBackgroundWorkerContext() -> NSManagedObjectContext { 
     let managedObjectContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType) 
     managedObjectContext.parentContext = self.mainContext 

     return managedObjectContext 
    } 

    class func newProduct(context context: NSManagedObjectContext) -> Product { 
     let newProduct = NSEntityDescription.insertNewObjectForEntityForName("Product", inManagedObjectContext: context) as! Product 

     return newProduct 
    } 

} 

createProduct関数が実行され、新しいPrivateQueueConcurrencyType管理オブジェクトコンテキスト:


の例では、文字列属性skuとXcodeのテンプレートが提供するデフォルトCoreDataスタックでCoreDataエンティティProductを前提としてい(MOC)は、新しいProduct管理オブジェクト(MO)によって販売され、使用されます。このコードは正しく動作しています。

ただし、私はcreateProduct関数の最初の2行を組み合わせた場合、そのようなこと:

let newProduct = CoreDataHelpers.newProduct(context: CoreDataHelpers.vendBackgroundWorkerContext()) 

は、アプリが EXC_BAD_ACCESStry newProduct.managedObjectContext?.save()でクラッシュします。

これはちょっと変わったように見えます。私たちがしたのはコードをリファクタリングしたものです。 documentationを調べると、managedObjectContextプロパティはunowned(unsafe)と宣言されています。これはおそらく、作成されたMOCの割り当てが解除されたことを意味し、ダングリングポインタ(私の前提が間違っていれば私を修正してください)があります。

MOCが確実に割り当て解除されないように、私はそれをMO自体に関連付けようとしました。 newProduct

class func newProduct(context context: NSManagedObjectContext) -> Product { 
    let newProduct = NSEntityDescription.insertNewObjectForEntityForName("Product", inManagedObjectContext: context) as! Product 

    var key: UInt8 = 0 
    objc_setAssociatedObject(newProduct, &key, context, .OBJC_ASSOCIATION_RETAIN) 

    return newProduct 
} 

これは、私がInstrumentsにチェックインするまで、素晴らしいことです。 (ソースオブジェクトの割り当てが解除されたときに、それが自動的に解放すべきではない?)Product MOが割り当て解除されたときに、今、関連するMOCがでないように思われる

私の質問は次のとおりです。 は、誰かが説明することができますどこの追加参照それが割り当て解除されないようにするMOCにありますか?私はMOとMOCの間に維持サイクルを作りましたか?

enter image description here

答えて

0

あなたはおそらく(サイクルを保持)、円形の所有権を作成しています。

すべての管理対象オブジェクトは管理コンテキスト(コンテキストがオブジェクトを所有)によって所有され、コンテキストを関連オブジェクトとして設定することは、オブジェクトが現在コンテキストも所有していることを意味します。

したがって、割り当て解除されません。

本当の解決策は、背景のコンテキストをmainContextで行っているローカルプロパティに保存することです。

+0

オンデマンドでワーカーコンテキストを破棄/作成しないでください。例えば。変更されている2つのMOはまだ保持されていません。同じ文脈であれば、保存は両方のMOに保存されます - あなたはそのうちの1つを永続させたいかもしれません)。複数のワーカーコンテキストを販売する注目すべきCDスタック(例:https://www.bignerdranch.com/blog/introducing-the-big-nerd-ranch-core-data-stack/)。 –

+0

@SoOverItあなたが正しいです、私は私の答えの最後の部分を削除しました。ただし、使用している管理されたコンテキストに強い参照があることを確認する必要があります。 – Sulthan

+0

「すべての管理対象オブジェクトは管理されたコンテキストによって所有されています」と言います。これは完全に真実ではありません。コンテキストが削除された管理対象オブジェクトを引き続き使用することができます。 NSManagedObjectクラスリファレンスのmanagedObjectContextのドキュメントを参照してください (https://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObject_Class/#//apple_ref/occ/instp/NSManagedObject/ managedObjectContext) - "受信者がそのコンテキストから削除された場合はゼロになることがあります。" –

関連する問題