64 votes

Xcode 8 génère des sous-classes NSManagedObject cassées pour iOS 10

J'ai récemment mis à jour mon projet d'application iOS vers iOS 10. J'essaie maintenant de modifier le Core Data Model de mon application, mais les nouvelles sous-classes NSManagedObject générées par Xcode sont cassées. J'ai également essayé de corriger les sous-classes manuellement mais cela ne fonctionne pas.

La version minimale des outils pour le Core Data Model est définie sur Xcode 7.0 et le langage de génération de code est défini sur Swift.

C'est le code que Xcode génère :

import Foundation
import CoreData
import 

extension Group {

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

    @NSManaged public var name: String?
    @NSManaged public var platform: NSNumber?
    @NSManaged public var profiles: NSOrderedSet?

}

// MARK: Generated accessors for profiles
extension Group {

    @objc(insertObject:inProfilesAtIndex:)
    @NSManaged public func insertIntoProfiles(_ value: SavedProfile, at idx: Int)

    @objc(removeObjectFromProfilesAtIndex:)
    @NSManaged public func removeFromProfiles(at idx: Int)

    @objc(insertProfiles:atIndexes:)
    @NSManaged public func insertIntoProfiles(_ values: [SavedProfile], at indexes: NSIndexSet)

    @objc(removeProfilesAtIndexes:)
    @NSManaged public func removeFromProfiles(at indexes: NSIndexSet)

    @objc(replaceObjectInProfilesAtIndex:withObject:)
    @NSManaged public func replaceProfiles(at idx: Int, with value: SavedProfile)

    @objc(replaceProfilesAtIndexes:withProfiles:)
    @NSManaged public func replaceProfiles(at indexes: NSIndexSet, with values: [SavedProfile])

    @objc(addProfilesObject:)
    @NSManaged public func addToProfiles(_ value: SavedProfile)

    @objc(removeProfilesObject:)
    @NSManaged public func removeFromProfiles(_ value: SavedProfile)

    @objc(addProfiles:)
    @NSManaged public func addToProfiles(_ values: NSOrderedSet)

    @objc(removeProfiles:)
    @NSManaged public func removeFromProfiles(_ values: NSOrderedSet)

}

Edit : Ce sont les erreurs spécifiques que Xcode donne :

1. Group+CoreDataProperties.swift:13:1: Expected identifier in import declaration (the empty import)
2. Group+CoreDataProperties.swift:13:11: 'Group' is ambiguous for type lookup in this context
3. Group+CoreDataProperties.swift:15:16: Cannot specialize non-generic type 'NSFetchRequest'
4. Group+CoreDataProperties.swift:26:11: 'Group' is ambiguous for type lookup in this context
4. Group+CoreDataProperties.swift:43:82: 'SavedProfile' is ambiguous for type lookup in this context

0 votes

Pouvez-vous expliquer ce qui est cassé ? Est-ce l'importation vide à la ligne 3 ?

0 votes

@DavidAtkinson Oui, Xcode donne une erreur pour l'importation vide. Il y a également 4 autres erreurs que j'ai ajoutées à la question.

4 votes

Malheureusement, je pense que c'est un bug dans Xcode 8 et 8.1 beta. Il se manifeste également lorsque les fichiers de données dérivées sont présents, si vous les générez automatiquement, mais Xcode recherche les fichiers avec un . au début du nom du fichier. Si vous corrigez manuellement ce problème, vous obtenez alors de fausses erreurs, comme celles que vous avez énumérées. Je n'ai pas encore trouvé de solution et je ne peux pas croire que plus de personnes n'ont pas trouvé cette erreur car elle semble vous empêcher de travailler avec les données de base dans une application. openradar.me/27151410

109voto

Longmang Points 8

J'ai finalement réussi à faire fonctionner le mien. Voici ce que j'ai fait. (Les vols sont une de mes entités)

J'ai configuré le xcdatamodeld comme suit

enter image description here

Et ensuite l'entité comme

enter image description here

Puis j'ai utilisé l'éditeur -> Créer une sous-classe de NSManagedObject

Cela crée deux fichiers pour l'entité de mes vols

Vols+CoreDataProperties.swift

Vols+CoreDataClass.swift

J'ai renommé Flights+CoreDataClass.swift en Flights.swift

Flights.swift est juste

import Foundation
import CoreData

@objc(Flights)
public class Flights: NSManagedObject {

}

Vols+CoreDataProperties.swift est

import Foundation
import CoreData

extension Flights {

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

    @NSManaged public var ...
}

Je n'ai pas réussi à faire fonctionner Codegen d'une autre manière, même si j'ai essayé plusieurs des suggestions qui existaient.

J'ai aussi eu du mal à comprendre pendant un moment et je l'ajoute comme aide. N'oubliez pas qu'avec la nouvelle version Generics de FetchRequest, vous pouvez faire ceci

let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Flights")

0 votes

C'est la réponse qui a fonctionné pour moi. J'ai passé une demi-journée à chercher la solution et il s'agissait d'un simple réglage. Je devrais chercher par défaut des trucs comme ça quand je commence à patauger. Merci !

4 votes

Cela a marché pour moi, merci beaucoup ! J'ai également passé beaucoup trop de temps à essayer de trouver une solution, avec pour résultat une frustration extrême. J'ai essayé toutes les solutions possibles et imaginables, et rien n'a marché à part celle-ci. Il est impératif que vous sélectionniez Manual/None pour le Codegen option. Si cela reste comme Class Definition il semble que cela ne fonctionnera pas. Merci encore pour votre aide !

0 votes

Merci. Ça a marché pour moi aussi. Mais c'est si délicat. Est-ce un bug de Xcode ?

43voto

Ryan H. Points 1829

Je pense que la raison pour laquelle vous avez rencontré ces erreurs après avoir généré les fichiers de sous-classe NSManagedObject peut être liée à l'option Codegen qui a été sélectionnée au moment où votre modèle de données a changé.

Je ne pense pas qu'il s'agisse d'un bogue. Du moins pas dans Xcode 8.1 (8B62).

J'ai rencontré un problème similaire et je l'ai résolu en changeant l'option Codegen en "Manual/None" et en laissant l'option Module en "Global Namespace". J'ai ensuite généré mes fichiers de sous-classe NSManagedObject. Cependant, selon votre situation, vous n'aurez peut-être même pas besoin de générer les sous-classes NSManagedObject.

Vous trouverez ci-dessous plus de détails sur les options Codegen de l'entité, en fonction de mon examen de la documentation d'Apple, du forum des développeurs d'Apple et des tests effectués sur mon propre projet.

Option 1 : "Définition de la classe".

  • Considérez cela comme l'option "plug and play".

  • Utilisez l'éditeur de modèle pour créer les entités et les attributs associés. que vous voulez que Core Data gère.

  • N'utilisez pas le générateur de sous-classes NSMangagedObject. Les fichiers fichiers requis sont automatiquement générés par Xcode (cependant ils n'apparaissent pas n'apparaissent pas dans votre navigateur de projet).

  • Si vous générez les fichiers NSManagedObject, Apple vous indique que ces fichiers ne doivent pas être modifiés dans les commentaires d'en-tête desdits fichiers. Si vous avez besoin de modifier ces fichiers, c'est un bon signe. que vous devez utiliser une autre option de Codegen.

  • Laissez les options de classe par défaut pour votre entité (Module = Global Namespace et Codegen = Class Definition).

  • Si vous avez besoin de remplacer les méthodes de NSManagedObject, vous pouvez utiliser les méthodes suivantes créer une extension en utilisant le nom sous l'option Classe.

    // Optional extension in Entity.swift extension Entity { // Override NSManagedObject methods }

Options 2 : "Manuel/Aucun"

  • Semblable à l'option 1, sauf que vous pouvez voir et modifier l'adresse de l'utilisateur. fichiers de sous-classe NSManagedObject.

  • Utilisez l'éditeur de modèle pour créer les entités et les attributs associés. que vous voulez que Core Data gère.

  • Avant d'utiliser le générateur de sous-classes NSManagedObject, définissez l'option Codgen à "Manual/None" pour l'entité. L'option Module doit être Espace de noms global.

  • Après avoir ajouté/supprimé/mis à jour un attribut, vous avez deux choix : (1) Mettre à jour manuellement les fichiers NSManagedObject qui ont été générés pour vous OU (2) Utiliser à nouveau le générateur de sous-classes NSManagedObject (ceci ne mettra seulement le fichier Entity+CoreDataProperties.swift).

  • Encore une fois, si vous avez besoin de surcharger les méthodes de NSManagedObject, vous devez pouvez créer une extension. L'extension doit être créée dans le fichier Entity+CoreDataClass.swift et non dans le fichier Entity+CoreDataProperties.swift (ce fichier pourrait être mis à jour suite à des des modifications de l'éditeur de modèle).

    // Optional extension in Entity+CoreDataClass.swift extension Entity { // Override NSManagedObject methods }

Option 3 : "Catégorie/extension".

  • Utilisez cette option si vous avez des propriétés personnalisées qui n'ont pas besoin d'être gérées par Core Data.

  • Utilisez l'éditeur de modèle pour créer les entités et les attributs associés. que vous voulez que Core Data gère.

  • Assurez-vous que l'option Module est réglée sur Current Product Module et que l'option Codegen est réglée sur "Catégorie/Extension".

  • Créez votre propre sous-classe NSManagedObject avec les propriétés que vous souhaitez gérerez vous-même.

  • N'utilisez pas le générateur de sous-classes NSMangagedObject. Les fichiers requis nécessaires sont automatiquement générés par Xcode (mais ils n'apparaissent pas n'apparaissent pas dans votre navigateur de projet).

    // Subclass NSManagedObject in Entity.swift class Entity: NSManagedObject { // Self managed properties }

    // Optional extension in Entity.swift extension Entity { // Override NSManagedObject methods }

3 votes

Pouvez-vous détailler un peu plus le chemin de la catégorie/extension ? J'ai ajouté une propriété transitoire dans le modèle de données et je ne sais pas comment modifier les fichiers qui ont été générés car je ne les vois pas dans l'explorateur de fichiers de gauche. Ils apparaissent lors de l'importation des en-têtes, ils doivent donc être générés quelque part.

0 votes

Merci. Votre réponse a été extrêmement utile. Pouvez-vous également jeter un coup d'œil aquí . Ma question porte sur la manière dont on peut modifier les propriétés lorsque l'on utilise Manuel/Aucun

40voto

akshay Points 645
  1. Pour résoudre ce problème, supprimez les données dérivées de l'application.

  2. Ensuite, changez le Module a Module de produit actuel et apporte également des modifications dans Codegen a Manuel/Aucun .

  3. List item

1 votes

Si vous souhaitez sauter la suppression des données dérivées, supprimez la sous-classe NSManagedObject que vous avez créée, apportez les modifications ci-dessus, enregistrez le fichier de modèle, puis créez à nouveau la sous-classe NSManagedObject.

1 votes

Voici comment le réparer

17voto

Daniel Chepenko Points 692

Essayez de définir CodeGen : Manuel/Non Module : Module du produit actuel

Cela a bien fonctionné pour moi, lorsque j'ai été confronté au même problème.

enter image description here

10voto

SamBundy Points 91

Vous pouvez essayer les étapes suivantes

  1. Sélectionnez le .xcdatamodeld dans le navigateur de projet Xocde
  2. En el Inspecteur du module de données assurez-vous que Codegen : Manuel/Aucun
  3. Puis Modifier -> Créer une sous-classe NSManagedObject
  4. Nettoyer le produit et le reconstruire

C'est du travail ? Si non

Assurez-vous que vous classe n'a pas le même nom que Entités . Vous pouvez trouver ces classes dans Phases de construction -> Compiler les sources . Renommer la classe ou les Entités si elles se sont dupliquées.

Ou

Vous pouvez exécuter cette commande dans le dossier de votre projet pour obtenir plus d'informations sur les erreurs.

xcodebuild -verbose

J'ai reçu ce message lorsque j'ai eu ce problème

duplication du symbole _OBJC_CLASS_$_RandomList dans :

xxxx/RandomList.o

xxxx/RandomList+CoreDataClass.o

RandomList.h y RandomList+CoreDataClass.h ont un même symbole lors de la compilation

Je pense que c'est la raison pour laquelle Xcode ne vous a pas averti, mais le compilateur va lancer une erreur.

J'espère que cela vous aidera

0 votes

Si vous avez déjà créé les deux fichiers, les numéros 2 et 3 suffisent. Cela fonctionne pour moi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X