2014-07-08 3 views
5

Sto utilizzando Swift su Xcode 6 con CoreData.Problemi di casting Swift e CoreData in test vs non test

Ho letto le note di rilascio e ho visto questo issue di fare in modo di segnare un modello di dati di base con un nome del modulo (nome dell'applicazione) in modo da poter lanciare un NSManagedObject al vostro tipo di modello in fase di esecuzione.

Quando eseguo questa operazione, riesco a far funzionare correttamente un'applicazione (buona!). Tuttavia, il mio problema è che quando cerco di prova che lo stesso codice, il test sarà sempre in crash ogni volta che il cast avviene con un Swift dynamic cast failed errore (male :(). Questo rende difficile per testare la mia applicazione.

Is ? esiste un impatto sul nome del modulo che usiamo quando l'applicazione è costruita per il test contro l'esecuzione

Grazie in anticipo per qualsiasi puntatori ...

Follow up:

Questo non è l'ideale: Come indicato sopra, per consentire a Swift di utilizzare un Core D ata model, devi decorare il nome della classe con il nome della tua app. Questo funziona per la creazione dell'app, ma i test vengono eseguiti con un nome app diverso! Ciò significa che è necessario andare nel modellatore dati e modificare il nome della classe da myAppname.myEntity a myAppnameTests.myEntity prima di poter utilizzare tali entità per nome quando utilizzate o richiamate da un test.

+0

Provare a decorare il nome della classe con @objc (MyClassName). Questo eviterà il normale mangling del nome. Quindi non dovresti preoccuparti del nome del modulo nel modello dati. –

+0

Se scrivo le mie classi di entità in swift, quindi le decoriamo usando 'objc (xxx)' - Ricevo l'errore di cast dinamico ogni volta che provo a usare l'entità con quel nome in un altro codice rapido ... Frustrante ... –

+0

Prova questo: http://stackoverflow.com/a/26568813/438063 – Lucien

risposta

1

È necessario aggiungere una riga a voi Entity.swift file per renderlo anche una classe Objective-C come questo:

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

Penso che questo come un bug se il progetto non contiene alcun objective- codice c. Tuttavia, è necessario aggiungere quella linea fino a quando non è stato risolto.

L'ho imparato da qui.

Youtube video at 11:45

+0

Il mio progetto ha codice obiettivo c - ma i problemi che sto riscontrando sono quando il codice swift chiama (o prova a chiamare) Swift Core Data Code ... :( –

+0

Quindi puoi provare il mio metodo. il mio metodo, non è necessario aggiungere personale di nomi di app all'entità. Basta lasciarlo da solo con il suo nome di classe. –

4

Il tuo è tutto giusto, il problema è il quando si esegue l'applicazione che sta cercando myAppname.myEntity e quando si esegue come prova che sta cercando come myAppnameTests.myEntity. La soluzione che uso in questo momento (Xcode 6.1) NON deve riempire il campo Class nell'interfaccia utente CoreData e farlo invece nel codice.

Questo codice rileverà se si esegue come App vs Test e si utilizza il nome del modulo corretto e si aggiorna lo 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

Se vuoi che il tuo moduleName sia dinamico (invece di codificarlo), usa 'NSBundle.mainBundle(). InfoDictionary? [" CFBundleName "]!'. Dovrebbe tornare "Streak" –