2014-07-08 6 views
5

Ich verwende Swift auf Xcode 6 mit CoreData.Swift und CoreData Casting Probleme im Test vs Nicht-Test

Ich habe die Versionshinweise gelesen und habe diese issue gesehen, um sicherzustellen, dass ein Kerndatenmodell mit einem Modulnamen (App-Name) markiert wird, sodass Sie zur Laufzeit einen NSManagedObject in Ihren Modelltyp umwandeln können.

Wenn ich dies tue, kann ich eine App richtig laufen lassen (gut!). Aber mein Problem ist, wenn ich zu Test versuchen dass gleiche Code, der Test wird immer abstürzen, wenn die Besetzung mit einem Fehler Swift dynamic cast failed passiert (schlecht :(). Dies macht es schwierig, meine Anwendung zu testen.

Ist ? es einen Einfluss auf die Modulnamen verwenden wir, wenn die Anwendung für den Test gegen laufen gebaut

Vielen Dank im Voraus für alle Hinweise ...

Follow up:

das ist nicht ideal: Wie oben erwähnt, um Swift einen Core D zu verwenden Bei einem Modell müssen Sie den Klassennamen mit dem Namen Ihrer App dekorieren. Dies funktioniert zum Erstellen der App, aber die Tests laufen unter einem anderen App-Namen! Das bedeutet, dass Sie in den Datenmodellierer gehen und diesen Klassennamen von myAppname.myEntity in myAppnameTests.myEntity ändern müssen, bevor Sie diese Entitäten namentlich verwenden können, wenn sie von einem Test verwendet oder aufgerufen werden.

+0

Versuchen Sie, den Klassennamen mit @objc (MyClassName) zu dekorieren. Dies wird den normalen Namensmangel umgehen. Dann sollten Sie sich im Datenmodell nicht um den Modulnamen kümmern müssen. –

+0

Wenn ich meine Entity-Klassen in swift schreibe, dann dekoriere sie mit 'objc (xxx)' - Ich bekomme den dynamischen Cast-Fehler, wenn ich versuche, die Entity mit diesem Namen in anderen Swift-Code zu verwenden ... Frustrating ... –

+0

Versuchen dies: http://stackoverflow.com/a/26568813/438063 – Lucien

Antwort

1

Sie benötigen eine Zeile hinzufügen, um Sie es auch eine Objective-C-Klasse wie diese machen Entity.swift Datei:

@objc(YourEntity) 
class YourEntity: NSManagedObject { 
    ... 
} 

Ich denke, dies als ein Fehler, wenn Ihr Projekt enthält keine objektiv- c-Code. Sie müssen diese Zeile jedoch hinzufügen, bis dies behoben ist.

Ich habe es von hier gelernt.

Youtube video at 11:45

+0

Mein Projekt hat objektiven c-Code - aber die Probleme, die ich habe, sind, wenn Swift Core Data Code (oder versuchen zu rufen) Swift Core Data Code ... :( –

+0

So können Sie meine Methode versuchen. Es funktioniert für mich Bei meiner Methode müssen Sie keine Entitäten für App-Namen zu Entitäten hinzufügen, sondern nur den Klassennamen. –

4

Sie sind völlig Recht, die Frage der, wenn Sie die App starten Sie es sucht nach myAppname.myEntity und wenn Sie sich als Testlauf sieht es als myAppnameTests.myEntity. Die Lösung, die ich zu diesem Zeitpunkt verwende (Xcode 6.1), besteht darin, das Feld Class in der CoreData-UI NICHT zu füllen und stattdessen Code zu verwenden.

Dieser Code erkennt, ob Sie als App vs Tests ausgeführt werden, und verwenden Sie den richtigen Modulnamen und aktualisieren Sie die managedObjectClassName.

lazy var managedObjectModel: NSManagedObjectModel = { 
    // The managed object model for the application. This property is not optional... 
    let modelURL = NSBundle.mainBundle().URLForResource("Streak", withExtension: "momd")! 
    let managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)! 

    // Check if we are running as test or not 
    let environment = NSProcessInfo.processInfo().environment as [String : AnyObject] 
    let isTest = (environment["XCInjectBundle"] as? String)?.pathExtension == "xctest" 

    // Create the module name 
    let moduleName = (isTest) ? "StreakTests" : "Streak" 

    // Create a new managed object model with updated entity class names 
    var newEntities = [] as [NSEntityDescription] 
    for (_, entity) in enumerate(managedObjectModel.entities) { 
     let newEntity = entity.copy() as NSEntityDescription 
     newEntity.managedObjectClassName = "\(moduleName).\(entity.name)" 
     newEntities.append(newEntity) 
    } 
    let newManagedObjectModel = NSManagedObjectModel() 
    newManagedObjectModel.entities = newEntities 

    return newManagedObjectModel 
}() 
+1

Wenn Sie möchten, dass Ihr Modulname dynamisch ist (anstatt ihn hart zu codieren), verwenden Sie 'NSBundle.mainBundle(). InfoDictionary? [" CFBundleName "]!'. Es sollte "Streak" zurückgeben –