web-dev-qa-db-fra.com

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 avec iOS 10. J'essaie maintenant de modifier le modèle de données principal de mon application, mais les nouvelles sous-classes NSManagedObject générées par Xcode sont endommagées. J'ai aussi essayé de corriger le manuel des sous-classes mais cela ne fonctionne pas.

La version minimale des outils pour 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 généré par Xcode:

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: Voici 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
61
Remco Beugels

J'ai finalement eu le mien au travail. Voici ce que j'ai fait. (Vols est l'une de mes entités)

J'ai installé le xcdatamodeld comme suit

 enter image description here

Et puis l'entité en tant que

 enter image description here

Ensuite j'ai utilisé Editor -> Create NSManagedObject Subclass

Cela crée deux fichiers pour mon entité de 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 {

}

Flights + CoreDataProperties.Swift est

import Foundation
import CoreData


extension Flights {

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

    @NSManaged public var ...
}

Cela semble fonctionner pour moi. Je ne pouvais pas obtenir que Codegen fonctionne de toute autre manière, même si j’ai essayé la plupart des suggestions proposées.

De plus, cela me faisait me gratter la tête pendant un moment et je l’ajoute comme aide. N'oubliez pas qu'avec la nouvelle version générique de FetchRequest, vous pouvez le faire.

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

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 sélectionnée au moment de la modification de votre modèle de données.

Je ne pense pas que ce soit un bug. Du moins pas dans Xcode 8.1 (8B62).

J'ai rencontré un problème similaire et l'ai corrigé en modifiant l'option Codegen en "Manuel/Aucun" et en laissant l'option Module en "Espace de noms global". J'ai ensuite généré mes fichiers de sous-classe NSManagedObject. Toutefois, selon votre situation, il se peut que vous n’ayez même pas besoin de générer les sous-classes NSManagedObject. 

Vous trouverez ci-dessous des informations plus détaillées sur les options de l'entité Codegen basées sur mon examen de la documentation Apple, le forum du développeur Apple et les tests réalisés avec mon propre projet.

Option 1: "Définition de classe"

  • Pensez à 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 souhaitez que Core Data gère.

  • N'utilisez pas le générateur de sous-classe NSMangagedObject. Les fichiers Requis sont générés automatiquement pour vous par Xcode (cependant, ils ne s'affichent pas dans le 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 de ces fichiers Si vous avez besoin d'éditer ces fichiers, cela signifie que vous devez utiliser une autre option Codegen.

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

  • Si vous devez remplacer les méthodes de NSManagedObject, vous pouvez créer une extension à l’aide de l’option Nom sous la classe.

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

Option 2: "Manuel/Aucun"

  • Identique à l'option 1, sauf que vous pouvez voir et éditer les fichiers de sous-classe NSManagedObject.

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

  • Avant d'utiliser le générateur de sous-classe NSManagedObject, définissez l'option Codgen Sur "Manuel/Aucun" pour l'entité. L'option Module devrait êtreGlobal Namespace.

  • Après avoir ajouté/supprimé/mis à jour un attribut, vous avez le choix: (1) Mettez à jour manuellement les fichiers NSManagedObject générés pour vous OU (2) Utilisez à nouveau le générateur de sous-classe NSManagedObject (cela permettra. mettre à jour uniquement le fichier Entity + CoreDataProperties.Swift).

  • De nouveau, si vous devez remplacer des méthodes à partir de NSManagedObject, vous 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 peut être mis à jour en raison de la modification 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 qu'il n'est pas nécessaire de gérer Par Core Data.

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

  • Assurez-vous que l'option Module est définie sur Module produit actuel et que l'option Codegen est définie sur "Catégorie/Extension".

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

  • N'utilisez pas le générateur de sous-classe NSMangagedObject. Les fichiers Requis sont générés automatiquement pour vous par Xcode (cependant, ils ne s'affichent pas dans le navigateur de projet).

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

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

42
Ryan H.
  1. Pour résoudre ce problème, supprimez les données dérivées de l'application.

  2. Modifiez ensuite le module en module de produit actuel et modifiez également Codegen en Manuel/Aucun.

  3.  List item
39
akshay

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

Cela a bien fonctionné pour moi, quand j'ai rencontré le même problème.

 enter image description here

17
Daniel Chepenko

Vous pouvez essayer ces étapes

  1. Sélectionnez le fichier .xcdatamodeld dans Xocde Project Navigator.
  2. Dans l'inspecteur Data Modul , assurez-vous que Codegen : Manual/None
  3. Puis Modifier -> Créer une sous-classe NSManagedObject
  4. Nettoyer le produit et reconstruire

Est-ce que le travail? Si non

Assurez-vous que tous class n'a pas le même nom avec Entities . Vous pouvez trouver ces classes dans Build Phases -> Compile Sources . Renommez la classe ou les entités si elles sont dupliquées

Ou

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

xcodebuild -verbose

J'ai eu ce message quand j'ai ce problème

symbole en double _OBJC_CLASS _ $ _ RandomList dans: 

xxxx/RandomList.o 

xxxx/RandomList + CoreDataClass.o

RandomList.h et RandomList + CoreDataClass.h ont le même symbole lors de la compilation

Je pense que pourquoi Xcode ne vous a pas prévenu, mais le compilateur jettera une erreur

J'espère que ceci vous aidera

9
SamBundy

Si vous avez une application héritée et que vous souhaitez continuer à ajouter manuellement des classes d'objets gérés

  1. Assurez-vous que votre modèle de données de base codegen est défini sur Manuel/Aucun
  2. Sélectionnez votre fichier de modèle de données principal
  3. Créer une sous-classe d'objets gérés

 screenshot of editor

7
Neil Japhtha

Supprimez la 3ème instruction import car elle est vide.

Remarque: je ne sais pas pourquoi cela se produit, mais je suppose que c'est un bogue dans Xcode 8. Supprimez-le et tout ira bien.

6
Lawrence413

Sur Xcode 8.2.1, je l’ai fait comme ça: (merci pour Daniel Chepenko)

 enter image description here

Mais Xcode 8.2.1 ajoutera un stupide . dans les fichiers générés:

 enter image description here

Supprimez simplement le . et tout ira bien.

5
Alpha Liu

Je viens d'avoir un problème où je viens d'ajouter une entité Personne dans mon modèle au modèle Données de base. Puis généré la sous-classe NSManagedObject pour cela et il ne compilera pas, me donnant une erreur de l'éditeur de liens. Il s'avère que je suis censé changer l'option Codegen en Manuel/Aucun pour que cela fonctionne (voir la partie inférieure droite de l'image) .  enter image description here

4
ppalancica

Je pense que c'est un problème de xcode, où xcode génère une syntaxe incorrecte pour la classe de catégorie de données principale . Je crée un nsmanageobjectsubclass pour une entité AgentDetailsIt is creating the following classes

Ici, xcode crée une structure de code incorrecte dans AgentDetails+CoreDataClass.h et AgentDetails+CoreDataClass.m. Ceux-ci ont une structure de code comme:

enter image description here

Et 

enter image description here

Donc, il y a un problème d'interface en double puisque AgentDetails.h a la même interface.

Maintenant, pour résoudre ce problème, vous devez changer le code dans AgentDetails+CoreDataClass.h

enter image description here

et AgentDetails+CoreDataClass.m comme ceci:

enter image description here

3
souvickcse

Dans Data Model Inspector, sélectionnez Current Product Module sous 'Module' et Manual/None sous 'Codegen'. (Cela vous permet d'éditer des fichiers de sous-classe et de régénérer CoreDataProperties.Swift lorsque vous modifiez vos attributs sous la même entité.) 

 enter image description here

Vous pouvez ensuite choisir Create NSManagedObjectSubclass dans le menu Editor. Xcode créera 2 fichiers pour vous YourEntity + CoreDataClass.Swift et YourEntity + CoreDataProperties.Swift. Notez que si vous ne possédez pas le dernier Xcode (8.2.1), les propriétés facultatives/non optionnelles que vous avez définies dans votre inspecteur de modèle ne seront pas affichées correctement. Vous pouvez modifier le fichier YourEntity + CoreDataProperties.Swift. 

2
Ohmy

De même, si vous ajoutez vous-même une sous-classe NSManagedObject, n'oubliez pas de suivre l'étape suivante:

Cela a fonctionné pour moi.

1
Soumalya Banerjee

Xcode 8.1 semble générer la classe de modèle en interne. Supprimez simplement les 2 classes créées et vous pourrez toujours utiliser les entités de votre code.

Voici le message d'erreur que je recevais

<unknown>:0: error: filename "Recipe+CoreDataProperties.Swift" used twice: '/Users/Rick/Desktop/Devslop/Rick Recipe/Recipe+CoreDataProperties.Swift' and '/Users/Rick/Library/Developer/Xcode/DerivedData/Rick_Recipe-cctgjudvqobxlwetbcwmzrgxigwg/Build/Intermediates/Rick Recipe.build/Debug-iphonesimulator/Rick Recipe.build/DerivedSources/CoreDataGenerated/Rick_Recipe/Recipe+CoreDataProperties.Swift'
<unknown>:0: note: filenames are used to distinguish private declarations with the same name
Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1
1
user1988055

Je l'ai résolu comme un exemple donné ci-dessous

Créer CurrentcyPair.xcdatamodeld

sélectionnez CurrentcyPair.xcdatamodeld et sélectionnez Par défaut -> Entity (CurrencyPair), renommez la classe en (.ManagedCurrencyPair)

Sélectionnez Entity et ouvrez l'inspecteur. Définissez le code gen dans le modèle de données sur Manuel/Aucun

enter image description here

enter image description here

0
Wasim

J'ai trouvé ceci Message de David Atkinson qui est utile d'une certaine manière… .. Si je génère le code de la manière décrite par David. Je viens d'obtenir le code avec des erreurs de syntaxe et si je corrige les erreurs, tout fonctionne comme avant. Il ne manque aucun fichier commençant par '.' pas plus.

Les erreurs de syntaxe que je dois corriger sont - l’importation inutile - et certaines propriétés publiques qui ne sont pas destinées à être publiques dans mon code

0
tetanuss

Je mets mon grain de sel étant donné que je peux voir beaucoup de réponses qui résolvent le problème mais manquent la vraie raison derrière ce qui se passe vraiment ici.

Je suis tombé sur le même problème et en faisant une recherche rapide, j'ai pu constater que:

  • Avant Xcode 7, le comportement par défaut d'une entité Core Data était que le développeur devait créer et gérer manuellement les modifications des sous-classes NSManagedObject correspondantes. (Ceci peut et peut encore être accompli en utilisant le menu de l’éditeur en sélectionnant l’option "Créer une sous-classe NSManagedObject .."). 

  • À partir de Xcode 8, Apple a intégré un nouveau paramètre dans l'inspecteur de modèle de données nommé Codegen pour gérer et gérer les sous-classes NSManagedObject. La valeur par défaut de ce paramètre est "Définition de classe", qui indique à Xcode de générer les sous-classes NSManagedObject en fonction de nos entités définies au moment de la compilation et de les placer dans le dossier de données dérivé.

Avoir nos sous-classes NSManagedObject dans le projet + celles générées automatiquement par Xcode nous amène à la véritable raison derrière l'erreur de compilation "Plusieurs commandes produisent ..." car nous avons maintenant des modèles d'objets gérés dupliqués !!!

La solution consiste alors à utiliser l'un ou l'autre, pas les deux! Personnellement, je préfère avoir mes modèles d'objet géré dans le projet et j'ai donc changé le paramètre "Codegen" en "Manuel/Aucun". Si vous n’ajoutez pas de logique aux modèles, je parie que vous pouvez choisir de supprimer les modèles d’objet géré de votre projet et de laisser Xcode agir en fonction de la valeur "Définition de la classe" du paramètre mentionné. C’est la bonne façon de régler ce problème.

Vous pouvez trouver un excellent article expliquant tout cela en détail ici:

https://medium.com/@kahseng.lee123/core-data-codegen-explained-462c30341041

0

J'utilise la dernière version bêta de Xcode 8.1 (8T47).

Selon le journal des erreurs (voir ci-dessous), deux copies des fichiers générés automatiquement sont créées. Une copie est placée dans votre dossier de projet Xcode (celle visible dans votre répertoire dans la barre d’outils de gauche de Xcode), et une seconde copie est créée dans votre dossier DerivedData pour votre projet:

/Users/<your name>/Library/Developer/Xcode/DerivedData/<your app>-axhtnodotznxnrenefflktnxfeal/Build/Intermediates/<your app>.build/Debug-iphonesimulator/<your app>.build/DerivedSources/CoreDataGenerated/<your app>/<class name>+CoreDataProperties.Swift
/Users/<your name>/Library/Developer/Xcode/DerivedData/<your app>-axhtnodotznxnrenefflktnxfeal/Build/Intermediates/<your app>.build/Debug-iphonesimulator/<your app>.build/DerivedSources/CoreDataGenerated/<your app>/<class name>+CoreDataClass.Swift

La suppression des copies dans le répertoire de votre projet Xcode résoudra tous les problèmes, mais ne sert à rien, vous ne pouvez plus modifier ces fichiers ...

Je ne dirais pas que c'est une solution, mais plutôt une façon à moitié assommée de faire en sorte que le projet se construise. Espérons que ce bug sera bientôt résolu.

 Error Log

0
Mike

Pour ma part, j'ai créé les classes CocoaTouch en sous-classant manuellement NSManagedObject. Je règle le module en tant que module de produit actuel et Codegen en tant que catégorie/extension et cela fonctionne bien.

0
mstntsnr

Dans mon cas particulier, j'avais ajouté CoreData à un projet existant comportant déjà une classe Model du même nom que mon entité. La suppression de l'ancienne classe Model a résolu le problème, car son type entrait en collision avec la nouvelle classe CoreData Entity.

0
jonbauer