2017-04-05 2 views
0

Nouveauté des données de base et j'ai deux problèmes: Initialiser un NSManagedObject correctement et en conservant ses valeurs entre commodité et initialiseurs désignés.Initialisation de l'objet géré Données de base

Mon code dans mon AnalyticsEvent NSManagedObject sous-classe:

@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 
} 

Merci!

EDIT:

Une enquête plus approfondie peut révéler que peut-être est invoqué mon initialiseur de commodité par l'appel super.init(entity:insertInto:) et si elle est, je ne sais pas comment il trouve le sélecteur de la commodité initialiseur ... mais expliquerait pourquoi sa valeur (telle que l'horodatage) n'est pas retenue - parce que c'est une nouvelle instance de l'objet ?! Hmm ...

EDIT 2:

j'ai oublié de mentionner que je reçois cette erreur d'exécution lors de l'exécution frappe la ligne:

self.eventName = eventName 

CoreData: Erreur: un objet géré Mutating 0x7fa2da54da90 (0x7fa2da54da40) après avoir été retiré de son contexte.

Répondre

0

Je pense ce qui se passe ici est que vous devez faire init() aussi un initialiseur de commodité, et dans cet appel self.init(entity: event!, insertInto: database.managedObjectContext) (plutôt que super). Edit: J'ai eu un autre coup d'oeil à ceci aujourd'hui en essayant de créer un exemple de travail minimum, et n'a pas réussi à obtenir une erreur.

Je travaille avec une seule entité qui est un User qui a simplement un nom 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 est juste le code autogenerated que Xcode, mais a déménagé dans son propre objet:

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)") 
      } 
     } 
    } 
} 

Lorsque j'essaie de tester cela, j'obtiens le comportement attendu:

_ = 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 

Cependant, dans la classe User, lorsque j'ai quitté le singleton pour créer une nouvelle instance de CoreDataManager, par exemple.

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

ce changement a déclenché une « CoreData: erreur: un objet géré Mutating après qu'il a été retiré de son contexte. » Erreur. Donc, mon deuxième diagnostic de votre erreur est que cela vient de ne pas utiliser le même coordinateur de magasin persistant (et donc aussi, un contexte différent).

S'il est important que votre magasin persistant soit configurable (par ex.passer au nom du modèle) alors je pense qu'il serait mieux de passer au passage dans le contexte de l'initialiseur NSManagedObject, qui semble être plus d'un modèle commun de CoreData.

Sorte de réponse décousue, mais espérons que cette fois ce n'est pas un harcèlement!

+0

Merci, mais j'ai aussi essayé. Pas de chance! Il fournit également des erreurs d'exécution identiques. –

+0

@AlexSmith Je creuse dans les initialiseurs et ce que '@ NSManaged' signifie réellement maintenant ... Avez-vous vu cette réponse: http://stackoverflow.com/a/39239651/1060154 Je ne peux pas se porter garant pour cela, mais serait rapide à essayer! – MathewS

+0

Merci encore, mais malheureusement pas ce dont j'ai besoin. Comme avant ... –