2017-04-05 93 views
0

核心數據的新特性和我有兩個問題:正確初始化NSManagedObject,並保留其在便利和指定初始值設定項之間的值。初始化核心數據管理對象

我在我的AnalyticsEvent NSManagedObject子類代碼:

@NSManaged public var eventName: String? 
@NSManaged public var type: String? 
@NSManaged public var reference: String? 
@NSManaged public var timestamp: Double 

public required init() { 

    // Initialize CoreData stack... 
    let manager = CoreDataManager(modelName: "Analytics", storeName: "Analytics") 

    // I'm not sure what I should be using to instantiate a new entity here... 
    // I believe the entity(forEntityName:in:) class method should return an existing value stored in managedObjectContext... 
    let event = NSEntityDescription.entity(forEntityName: "Event", in: manager.managedObjectContext!) 

    // ... and insertNewObject(forEntityName:into:) to create a placeholder 
    // for my new object until I issue saveContext() on managedObjectContext. 
    // This isn't working right now, so comment out following line 
    //let event = NSEntityDescription.insertNewObject(forEntityName: "Event", into: database.managedObjectContext!) as! AnalyticsEvent 
    super.init(entity: event!, insertInto: database.managedObjectContext) 

    let customProperties = CustomProperties() 
    self.customPropertiesData = NSKeyedArchiver.archivedData(withRootObject: properties) as Data 
    self.timestamp = Date().timeIntervalSince1970 
} 

public convenience init(eventName: String) { 
    self.init() 

    // At this point the data set in my designated initializer (above), 
    // the values have been lost. For example, timestamp == 0 
    self.eventName = eventName 
    self.type = EventType.discreteEvent 
} 

謝謝!

編輯:

進一步調查可能會發現,也許我的便利初始化正在被super.init(entity:insertInto:)調用來調用,如果是,我不知道它是怎麼找到的便利初始化的選擇...但它會解釋爲什麼它的值(如時間戳)沒有被保留 - 因爲它是對象的新實例?!嗯......

編輯2:

我忘了說我得到這個運行時錯誤當執行到行:

self.eventName = eventName 

CoreData:錯誤:變異託管對象0x7fa2da54da90(0x7fa2da54da40 )在它從上下文中移除之後。

回答

0

認爲這裏發生了什麼是你需要做init()也便利初始化,並調用self.init(entity: event!, insertInto: database.managedObjectContext)(而不是super)內。

編輯:我今天試着創建一個最小的工作示例,並沒有得到一個錯誤,今天又看了一遍。

我用一個單一的實體是一個User,僅僅有一個名字property工作:

import Foundation 
import CoreData 

@objc(User) 
public class User: NSManagedObject { 

    @nonobjc public class func fetchRequest() -> NSFetchRequest<User> { 
     return NSFetchRequest<User>(entityName: "User") 
    } 

    @NSManaged public var name: String? 

    convenience init() { 
     let context = CoreDataManager.shared.persistentContainer.viewContext 
     self.init(context: context) 
     self.name = "Mathew" 
    } 

    convenience init(named name: String) { 
     self.init() 
     self.name = name 
    } 
} 

CoreDataManager僅僅是自動生成的代碼,Xcode的,但移動到它自己的對象:

import Foundation 
import CoreData 

class CoreDataManager { 

    static let shared = CoreDataManager() 

    lazy var persistentContainer: NSPersistentContainer = { 
     let container = NSPersistentContainer(name: "CoreDataInit") 
     container.loadPersistentStores(completionHandler: { (storeDescription, error) in 
      if let error = error as NSError? { 
       fatalError("Unresolved error \(error), \(error.userInfo)") 
      } 
     }) 
     return container 
    }() 

    func saveContext() { 
     let context = persistentContainer.viewContext 
     if context.hasChanges { 
      do { 
       try context.save() 
      } catch { 
       let nserror = error as NSError 
       fatalError("Unresolved error \(nserror), \(nserror.userInfo)") 
      } 
     } 
    } 
} 

當我嘗試測試這個,我得到預期的行爲:

_ = User() 
_ = User(named: "Marge") 
_ = User(named: "Homer") 

let fetchUsers: NSFetchRequest<User> = User.fetchRequest() 

if let results = try? CoreDataManager.shared.persistentContainer.viewContext.fetch(fetchUsers) { 
print("there are", results.count, "users") 

for user in results { 
    print("user is", user.name!) 
} 

// prints: 
// Mathew 
// Marge 
// Homer 

但是,在User類中,當我從單例轉移到創建例如CoreDataManager的新實例時,

//let context = CoreDataManager.shared.persistentContainer.viewContext 
let context = CoreDataManager().persistentContainer.viewContext 

這一變化引發了「CoreData:錯誤:變異的管理對象後,它已被從上下文中刪除。」錯誤。

所以我第二次診斷你的錯誤是它來自不使用相同的持久性存儲協調器(以及不同的上下文)。

如果持久性存儲可以配置(例如,爲了傳遞模型的名稱),那麼我認爲最好轉換到初始化程序,這似乎是更常見的CoreData模式。

排序一個漫無邊際的答案,但希望這一次它不是一個紅鯡魚!

+0

謝謝,但我也試過。沒有運氣!它也提供相同的運行時錯誤。 –

+0

@AlexSmith我正在研究初始化器和'@ NSManaged'實際上現在意味着什麼...你見過這個答案:http://stackoverflow.com/a/39239651/1060154我不能擔保它,但會快速嘗試! – MathewS

+0

再次感謝,但不幸的是不是我所需要的。和以前一樣... –