Sur mon application Lion, j'ai ce modèle de données:
La relation à l' subitems
intérieur Item
est ordonnée .
Xcode 4.1 (build 4B110) m'a créé pour le fichier Item.h
, Item.m
, SubItem.h
et SubItem.h
.
Voici le contenu (généré automatiquement) de Item.h
:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class SubItem;
@interface Item : NSManagedObject {
@private
}
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSOrderedSet *subitems;
@end
@interface Item (CoreDataGeneratedAccessors)
- (void)insertObject:(SubItem *)value inSubitemsAtIndex:(NSUInteger)idx;
- (void)removeObjectFromSubitemsAtIndex:(NSUInteger)idx;
- (void)insertSubitems:(NSArray *)value atIndexes:(NSIndexSet *)indexes;
- (void)removeSubitemsAtIndexes:(NSIndexSet *)indexes;
- (void)replaceObjectInSubitemsAtIndex:(NSUInteger)idx withObject:(SubItem *)value;
- (void)replaceSubitemsAtIndexes:(NSIndexSet *)indexes withSubitems:(NSArray *)values;
- (void)addSubitemsObject:(SubItem *)value;
- (void)removeSubitemsObject:(SubItem *)value;
- (void)addSubitems:(NSOrderedSet *)values;
- (void)removeSubitems:(NSOrderedSet *)values;
@end
Et voici le contenu (généré automatiquement) de Item.m
:
#import "Item.h"
#import "SubItem.h"
@implementation Item
@dynamic name;
@dynamic subitems;
@end
Comme vous pouvez le voir, la classe Item
propose une méthode appelée addSubitemsObject:
. Malheureusement, lorsque vous essayez de l'utiliser de cette façon:
Item *item = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:self.managedObjectContext];
item.name = @"FirstItem";
SubItem *subItem = [NSEntityDescription insertNewObjectForEntityForName:@"SubItem" inManagedObjectContext:self.managedObjectContext];
[item addSubitemsObject:subItem];
cette erreur apparaît:
2011-09-12 10:28:45.236 Test[2002:707] *** -[NSSet intersectsSet:]: set argument is not an NSSet
Pouvez-vous m'aider?
Mise à jour:
Après seulement 1 787 jours après mon rapport de bogue, Apple (1 août 2016) m'a écrit ceci: "Veuillez vérifier ce problème avec la dernière version bêta d'iOS 10 et mettre à jour votre rapport de bogue sur bugreport.apple.com avec vos résultats." . Espérons que ce soit le bon moment :)
mutableOrderedSetValueForKey:
)Réponses:
J'ai reproduit votre configuration à la fois avec votre modèle de données et la mienne avec des noms différents. J'ai eu la même erreur dans les deux cas.
Ressemble à un bogue dans le code généré automatiquement par Apple.
la source
Je suis d'accord qu'il peut y avoir un bug ici. J'ai modifié l'implémentation du setter d'objets add pour l'ajouter correctement à un NSMutableOrderedSet.
La réaffectation de l'ensemble à self.subitems garantit l'envoi des notifications Will / DidChangeValue.
la source
J'ai décidé d'améliorer la solution en implémentant toutes les méthodes requises:
la source
willChangeValueForKey:withSetMutation:usingObjects
ce que vous avez réussi à éviter. Après cela, utilisez simplement[[self primitiveValueForKey:ChildrenKey] unionOrderedSet:values]
ou[[self primitiveValueForKey:ChildrenKey] minusOrderedSet:values]
selon le cas. Voir ma réponse pour plus de détails.Oui, c'est définitivement un bogue Core Data. J'ai écrit un correctif basé sur ObjC-Runtime il y a quelque temps, mais à l'époque, je pensais que ce serait bientôt corrigé. Quoi qu'il en soit, pas de chance, donc je l'ai posté sur GitHub en tant que KCOrderedAccessorFix . Contournez le problème sur toutes vos entités:
Une entité en particulier:
Ou juste pour une relation:
la source
- (BOOL)kc_needsOrderedSetAccessorFix;
ou quelque chose qui vérifie la version Foundation / iOS.objc_msg_send
)Au lieu de faire une copie, je suggère d'utiliser l'accesseur dans NSObject pour avoir accès au NSMutableOrderedSet des relations.
Par exemple, les notes de publication de Core Data pour iOS v5.0 s'y réfèrent.
Dans un court test, cela a fonctionné dans mon application.
la source
NSStringFromSelector(@selector(subitems))
cependant :)J'ai suivi le bug. Cela se produit dans
willChangeValueForKey:withSetMutation:usingObjects:
.Cet appel déclenche une chaîne de notifications qui peut être difficile à suivre, et bien sûr, les modifications apportées à un intervenant peuvent avoir des implications pour un autre, ce qui, je pense, est la raison pour laquelle Apple n'a rien fait.
Cependant, il est correct dans Set et ce sont les seules opérations Set sur un OrderedSet qui fonctionnent mal. Cela signifie qu'il n'y a que quatre méthodes qui doivent être modifiées. Par conséquent, tout ce que j'ai fait a été de convertir les opérations Set en leurs opérations Array équivalentes. Ceux-ci fonctionnent parfaitement et avec des frais généraux minimes (mais nécessaires).
À un niveau critique, cette solution souffre d'un défaut critique; si vous ajoutez des objets et que l'un des objets existe déjà, il n'est pas ajouté ou déplacé à l'arrière de la liste ordonnée (je ne sais pas lequel). Dans les deux cas, l'indice ordonné attendu de l'objet au moment où nous arrivons
didChange
est différent de ce qui était prévu. Cela peut casser les applications de certaines personnes, mais cela n'affecte pas le mien, car j'ajoute uniquement de nouveaux objets ou je confirme leur emplacement final avant de les ajouter.Bien sûr, il existe une solution plus simple. c'est comme suit;
la source
Le document Apple To Many Relations dit: vous devez accéder à l'ensemble mutable proxy ou à l'ensemble ordonné en utilisant
La modification de cet ensemble ajoutera ou supprimera des relations avec votre objet géré. Accès à l'ensemble ordonné mutable à l'aide de l'accesseur avec [] ou. la notation est erronée et échouera.
la source
Reçu la même erreur, la solution @LeeIII a fonctionné pour moi (merci!). Je propose de le modifier légèrement:
Contenu de
Item+category.m
:la source
Si vous utilisez mogenerator, alors au lieu de
utilisez simplement:
la source
mogenerator
mais j'ai toujours le bug.Personnellement, je viens de remplacer les appels aux méthodes générées par CoreData par des appels directs à la méthode, comme indiqué dans une autre solution de @Stephan:
Cela supprime le besoin de catégories qui pourraient ultérieurement entrer en conflit avec une solution d'Apple au code généré lorsque le bogue est corrigé.
Cela a l'avantage supplémentaire d'être la façon officielle de le faire!
la source
addObject:
appelé deux fois?Il semble que si vous liez le parent à l'enfant en définissant le parent sur l'enfant et non l'inverse, cela fonctionne sans se bloquer.
Donc si vous le faites:
au lieu de
Cela devrait fonctionner, au moins cela fonctionne sur iOS 7 et n'a eu aucun problème avec la relation.
la source
J'ai eu le même problème, mais seulement quand j'ai essayé quelque chose de différent de ce que je faisais. Je ne peux pas voir le code de subItem, mais je suppose qu'il a un lien inverse vers l'élément. Appelons ce lien vénéré, "parentItem", alors la solution la plus simple est la suivante:
L'effet est qu'il utilise le propre code d'Apple et qu'il est simple et propre. De plus, l'ensemble est automatiquement ajouté et tous les observateurs sont mis à jour. Aucun problème.
la source
Je suis juste tombé sous le coup de ce problème et l'ai résolu en utilisant une implémentation beaucoup plus simple que les autres décrites ici. J'utilise simplement les méthodes disponibles sur
NSManagedObject
pour gérer les relations lorsque vous n'utilisez pas de sous-classes.Un exemple d'implémentation pour insérer une entité dans une
NSOrderedSet
relation ressemblerait à ceci:Cela fonctionne parfaitement et c'est ce que j'utilisais avant de passer aux
NSManagedObject
sous-classes.la source
Ce problème m'est apparu lors de la migration d'un projet d'Objective-C vers Swift 2 avec XCode 7 . Ce projet fonctionnait, et pour une bonne raison: j'utilisais MOGenerator qui avait des méthodes de remplacement pour corriger ce bogue. Mais toutes les méthodes ne nécessitent pas de remplacement.
Voici donc la solution complète avec un exemple de classe, en s'appuyant autant que possible sur les accesseurs par défaut.
Disons que nous avons une liste avec les articles commandés
D'abord une victoire rapide si vous avez une relation un à plusieurs, le plus simple est de simplement faire:
au lieu de
Maintenant, si ce n'est pas une option , voici ce que vous pouvez faire:
Bien sûr, si vous utilisez Objective-C, vous pouvez faire exactement la même chose puisque c'est là que j'ai eu l'idée en premier :)
la source
Leelll, êtes-vous sûr qu'après une telle configuration personnalisée des valeurs NSMutableOrderedSet stockées dans cet ensemble seront correctement enregistrées dans la base de données par CoreData? Je n'ai pas vérifié cela, mais il semble que CoreData ne sache rien de NSOrderedSet et attend NSSet comme conteneur de relation to-many.
la source
Je pense que tout le monde manque le vrai problème. Ce n'est pas dans les méthodes d'accesseur mais plutôt dans le fait qu'il
NSOrderedSet
ne s'agit pas d'une sous-classe deNSSet
. Donc, quand-interSectsSet:
est appelé avec un ensemble ordonné comme argument, il échoue.échoue avec
*** -[NSSet intersectsSet:]: set argument is not an NSSet
Il semble que le correctif consiste à modifier l'implémentation des opérateurs d'ensemble afin qu'ils gèrent les types de manière transparente. Aucune raison pour laquelle un
-intersectsSet:
devrait fonctionner avec un ensemble ordonné ou non ordonné.L'exception se produit dans la notification de modification. Vraisemblablement dans le code qui gère la relation inverse. Puisque cela ne se produit que si je mets une relation inverse.
Ce qui suit a fait l'affaire pour moi
la source
Je viens de recevoir le problème dans Swift (Xcode 6.1.1).
La réponse était NE PAS CODER DE MÉTHODE OU DE CHOSES SUPPLÉMENTAIRES CHOSE dans vos sous-classes NSManagedObject. Je pense que c'est une erreur de compilation. Bug très étrange ..
J'espère que cela aide ..
la source
J'ai résolu ce problème en définissant l'inverse sur No Inverse, je ne sais pas pourquoi, il y a peut-être Apple Bug.
la source
J'ai la même situation avec un élément appelé "signaux" au lieu de "sous-éléments". La solution avec tempset fonctionne dans mes tests. De plus, j'ai eu un problème avec la méthode removeSignals :. Cette dérogation semble fonctionner:
S'il existe une meilleure façon de procéder, veuillez me le faire savoir. Mes valeurs ne sont jamais plus de 10 à 20 éléments, donc les performances ne sont pas très préoccupantes - néanmoins, veuillez signaler tout ce qui est pertinent.
Merci,
Damien
la source
J'ai trouvé cette question en recherchant le message d'erreur sur Google, et je voulais juste souligner que j'ai rencontré cette erreur d'une manière légèrement différente (sans utiliser d'ensembles ordonnés). Ce n'est pas tout à fait une réponse à la question donnée, mais je la poste ici juste au cas où elle serait utile à toute autre personne qui tombe sur cette question lors de la recherche.
J'ajoutais une nouvelle version de modèle, ajoutais des relations aux modèles existants et définissais moi-même les méthodes add * Object dans le fichier d'en-tête. Lorsque j'ai essayé de les appeler, j'ai eu l'erreur ci-dessus.
Après avoir examiné mes modèles, j'ai réalisé que j'avais bêtement oublié de cocher la case "Relation à plusieurs".
Donc, si vous rencontrez cela et que vous n'utilisez pas d'ensembles ordonnés, vérifiez votre modèle.
la source
J'ai trouvé un correctif pour ce bug qui fonctionne pour moi. Je remplace juste ceci:
avec ça:
la source
Meilleure version de la bonne réponse dans SWIFT
la source
J'ai trouvé que l'utilisation de la méthode par LeeIII fonctionnait, mais sur le profilage, j'ai trouvé qu'elle était drastiquement lente. Il a fallu 15 secondes pour analyser 1000 éléments. Commenter le code pour ajouter la relation est passé de 15 secondes à 2 secondes.
Ma solution de contournement (qui est plus rapide mais beaucoup plus laide) consiste à créer un tableau mutable temporaire, puis à copier dans l'ensemble ordonné lorsque toute l'analyse est terminée. (ce n'est qu'une victoire de performance si vous allez ajouter de nombreuses relations).
J'espère que cela aide quelqu'un d'autre!
la source
Robert,
Je suis d'accord que votre réponse fonctionnera pour cela, mais gardez à l'esprit qu'il existe déjà une méthode créée automatiquement pour ajouter un ensemble de valeurs à une relation. La documentation d'Apple ( comme on le voit ici dans la section "Relations To-many" ou ici dans la section "Méthodes d'accesseur de relation Custom To-Many") les implémente de cette façon:
Vous pouvez facilement compiler votre ensemble de relations en dehors des données de base, puis les ajouter toutes à la fois en utilisant cette méthode. C'est peut-être moins moche que la méthode que vous avez suggérée;)
la source
Je suis sûr qu'il est finalement corrigé dans iOS 10 beta 6 !
la source