cocoa - property - Excepción lanzada en accesores generados por NSOrderedSet
transient property core data (25)
En mi aplicación Lion, tengo este modelo de datos:
Se ordenan los subitems
relación dentro del Item
.
Xcode 4.1 (compilación 4B110) ha creado para mí el archivo Item.h
, Item.m
, SubItem.h
y SubItem.h
.
Aquí está el contenido ( Item.h
) 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
Y aquí está el contenido (autogenerado) de Item.m
:
#import "Item.h"
#import "SubItem.h"
@implementation Item
@dynamic name;
@dynamic subitems;
@end
Como puede ver, el Item
clase ofrece un método llamado addSubitemsObject:
Desafortunadamente, al intentar usarlo de esta manera:
Item *item = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:self.managedObjectContext];
item.name = @"FirstItem";
SubItem *subItem = [NSEntityDescription insertNewObjectForEntityForName:@"SubItem" inManagedObjectContext:self.managedObjectContext];
[item addSubitemsObject:subItem];
este error aparece:
2011-09-12 10:28:45.236 Test[2002:707] *** -[NSSet intersectsSet:]: set argument is not an NSSet
¿Me puedes ayudar?
Actualizar:
Después de solo 1,787 días a partir de mi informe de errores, hoy (1 de agosto de 2016) Apple me escribió esto: "Verifique este problema con la última compilación beta de iOS 10 y actualice su informe de errores en bugreport.apple.com con sus resultados". . Esperemos que este sea el momento adecuado :)
Estoy de acuerdo en que tal vez haya un error aquí. He modificado la implementación del agregar objeto> setter para que se agregue correctamente a un NSMutableOrderedSet.
- (void)addSubitemsObject:(SubItem *)value { NSMutableOrderedSet* tempSet = [NSMutableOrderedSet orderedSetWithOrderedSet:self.subitems]; [tempSet addObject:value]; self.subitems = tempSet; }
Al reasignar el conjunto a self.subitems, se garantizará que se envíen las notificaciones Will / DidChangeValue>.
Leelll, ¿estás seguro de que después de dicha configuración personalizada de los valores de NSMutableOrderedSet almacenados en ese conjunto se guardarán en la base de datos correctamente mediante CoreData? No lo comprobé, pero parece que CoreData no sabe nada acerca de NSOrderedSet y espera que NSSet sea un contenedor de relaciones de muchos.
Creo que a todos les falta el problema real. No está en los métodos de acceso, sino en el hecho de que NSOrderedSet
no es una subclase de NSSet
. Entonces cuando se llama a -interSectsSet:
con un conjunto ordenado como argumento falla.
NSOrderedSet* setA = [NSOrderedSet orderedSetWithObjects:@"A",@"B",@"C",nil];
NSSet* setB = [NSSet setWithObjects:@"C",@"D", nil];
[setB intersectsSet:setA];
falla con *** -[NSSet intersectsSet:]: set argument is not an NSSet
Parece que la solución es cambiar la implementación de los operadores de conjunto para que manejen los tipos de manera transparente. No hay ninguna razón por la que un -intersectsSet:
debería trabajar con un conjunto ordenado o desordenado.
La excepción ocurre en la notificación de cambio. Presumiblemente en el código que maneja la relación inversa. Ya que solo pasa si establezco una relación inversa.
Lo siguiente hizo el truco para mí
@implementation MF_NSOrderedSetFixes
+ (void) fixSetMethods
{
NSArray* classes = [NSArray arrayWithObjects:@"NSSet", @"NSMutableSet", @"NSOrderedSet", @"NSMutableOrderedSet",nil];
[classes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString* name = obj;
Class aClass = objc_lookUpClass([name UTF8String]);
[MF_NSOrderedSetFixes fixMethodWithSetArgument:@selector(intersectsSet:) forClass:aClass];
[MF_NSOrderedSetFixes fixMethodWithSetArgument:@selector(isSubsetOfSet:) forClass:aClass];
}];
}
typedef BOOL (*BoolNSetIMP)(id _s,SEL sel, NSSet*);
/*
Works for all methods of type - (BOOL) method:(NSSet*) aSet
*/
+ (void) fixMethodWithSetArgument:(SEL) aSel forClass:(Class) aClass
{
/* Check that class actually implements method first */
/* can''t use get_classInstanceMethod() since it checks superclass */
unsigned int count,i;
Method method = NULL;
Method* methods = class_copyMethodList(aClass, &count);
if(methods) {
for(i=0;i<count;i++) {
if(method_getName(methods[i])==aSel) {
method = methods[i];
}
}
free(methods);
}
if(!method) {
return;
}
// Get old implementation
BoolNSetIMP originalImp = (BoolNSetIMP) method_getImplementation(method);
IMP newImp = imp_implementationWithBlock(^BOOL(NSSet *_s, NSSet *otherSet) {
if([otherSet isKindOfClass:[NSOrderedSet class]]) {
otherSet = [(NSOrderedSet*)otherSet set];
}
// Call original implementation
return originalImp(_s,aSel,otherSet);
});
method_setImplementation(method, newImp);
}
@end
Decidí mejorar la solución implementando todos los métodos requeridos:
static NSString *const kItemsKey = @"<#property#>";
- (void)insertObject:(<#Type#> *)value in<#Property#>AtIndex:(NSUInteger)idx {
NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];
[self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
[tmpOrderedSet insertObject:value atIndex:idx];
[self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
[self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)removeObjectFrom<#Property#>AtIndex:(NSUInteger)idx {
NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];
[self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
[tmpOrderedSet removeObjectAtIndex:idx];
[self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
[self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)insert<#Property#>:(NSArray *)values atIndexes:(NSIndexSet *)indexes {
[self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
[tmpOrderedSet insertObjects:values atIndexes:indexes];
[self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
[self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)remove<#Property#>AtIndexes:(NSIndexSet *)indexes {
[self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
[tmpOrderedSet removeObjectsAtIndexes:indexes];
[self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
[self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)replaceObjectIn<#Property#>AtIndex:(NSUInteger)idx withObject:(<#Type#> *)value {
NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];
[self willChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:kItemsKey];
NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
[tmpOrderedSet replaceObjectAtIndex:idx withObject:value];
[self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
[self didChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)replace<#Property#>AtIndexes:(NSIndexSet *)indexes with<#Property#>:(NSArray *)values {
[self willChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:kItemsKey];
NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
[tmpOrderedSet replaceObjectsAtIndexes:indexes withObjects:values];
[self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
[self didChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)add<#Property#>Object:(<#Type#> *)value {
NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
NSUInteger idx = [tmpOrderedSet count];
NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];
[self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
[tmpOrderedSet addObject:value];
[self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
[self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)remove<#Property#>Object:(<#Type#> *)value {
NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
NSUInteger idx = [tmpOrderedSet indexOfObject:value];
if (idx != NSNotFound) {
NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];
[self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
[tmpOrderedSet removeObject:value];
[self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
[self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
}
}
- (void)add<#Property#>:(NSOrderedSet *)values {
NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet];
NSUInteger valuesCount = [values count];
NSUInteger objectsCount = [tmpOrderedSet count];
for (NSUInteger i = 0; i < valuesCount; ++i) {
[indexes addIndex:(objectsCount + i)];
}
if (valuesCount > 0) {
[self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
[tmpOrderedSet addObjectsFromArray:[values array]];
[self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
[self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
}
}
- (void)remove<#Property#>:(NSOrderedSet *)values {
NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet];
for (id value in values) {
NSUInteger idx = [tmpOrderedSet indexOfObject:value];
if (idx != NSNotFound) {
[indexes addIndex:idx];
}
}
if ([indexes count] > 0) {
[self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
[tmpOrderedSet removeObjectsAtIndexes:indexes];
[self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
[self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
}
}
En lugar de hacer una copia, sugiero utilizar el descriptor de acceso en NSObject para obtener acceso al NSMutableOrderedSet de las relaciones.
- (void)addSubitemsObject:(SubItem *)value {
NSMutableOrderedSet* tempSet = [self mutableOrderedSetValueForKey:@"subitems"];
[tempSet addObject:value];
}
Por ejemplo, las Notas de la versión de Core Data para iOS v5.0 se refieren a esto.
En una breve prueba funcionó en mi aplicación.
Este problema se me ocurrió al migrar un proyecto de Objective-C a Swift 2 con XCode 7 . Ese proyecto solía funcionar, y por una buena razón: estaba usando MOGenerator, que tenía métodos de reemplazo para corregir este error. Pero no todos los métodos requieren un reemplazo.
Así que aquí está la solución completa con una clase de ejemplo, confiando en los accesores predeterminados tanto como sea posible.
Digamos que tenemos una lista con artículos pedidos
Primero, una ganancia rápida si tiene una relación de uno a muchos, lo más fácil es simplemente hacer:
item.list = list
en lugar de
list.addItemsObject(item)
Ahora, si esa no es una opción , esto es lo que puedes hacer:
// Extension created from your DataModel by selecting it and
// clicking on "Editor > Create NSManagedObject subclass…"
extension List {
@NSManaged var items: NSOrderedSet?
}
class List
// Those two methods work out of the box for free, relying on
// Core Data''s KVC accessors, you just have to declare them
// See release note 17583057 https://developer.apple.com/library/prerelease/tvos/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc7_release_notes.html
@NSManaged func removeItemsObject(item: Item)
@NSManaged func removeItems(items: NSOrderedSet)
// The following two methods usually work too, but not for NSOrderedSet
// @NSManaged func addItemsObject(item: Item)
// @NSManaged func addItems(items: NSOrderedSet)
// So we''ll replace them with theses
// A mutable computed property
var itemsSet: NSMutableOrderedSet {
willAccessValueForKey("items")
let result = mutableOrderedSetValueForKey("items")
didAccessValueForKey("items")
return result
}
func addItemsObject(value: Item) {
itemsSet.addObject(value)
}
func addItems(value: NSOrderedSet) {
itemsSet.unionOrderedSet(value)
}
end
Por supuesto, si estás usando Objective-C, puedes hacer exactamente lo mismo ya que aquí es donde obtuve la idea en primer lugar :)
Estoy de acuerdo en que puede haber un error aquí. He modificado la implementación del agregador de objetos agregados para adjuntarlos correctamente a un NSMutableOrderedSet.
- (void)addSubitemsObject:(SubItem *)value {
NSMutableOrderedSet* tempSet = [NSMutableOrderedSet orderedSetWithOrderedSet:self.subitems];
[tempSet addObject:value];
self.subitems = tempSet;
}
Reasignar el conjunto a self.subitems garantizará que se envíen las notificaciones Will / DidChangeValue.
He rastreado el error. Ocurre en willChangeValueForKey:withSetMutation:usingObjects:
Esta llamada desencadena una cadena de notificaciones que pueden ser difíciles de rastrear y, por supuesto, los cambios en un respondedor pueden tener implicaciones para otro, lo cual sospecho que Apple no ha hecho nada.
Sin embargo, está bien en Set y solo funcionan las operaciones Set en OrderedSet que funcionan mal. Eso significa que solo hay cuatro métodos que necesitan ser alterados. Por lo tanto, todo lo que hice fue convertir las operaciones de Set a sus operaciones de Array equivalentes. Estos funcionan perfectamente y los gastos generales mínimos (pero necesarios).
En un nivel crítico, esta solución sufre de una falla crítica; Si está agregando objetos y uno de los objetos ya existe, entonces no se agrega ni se mueve al final de la lista ordenada (no sé cuál). En cualquier caso, el índice ordenado esperado del objeto para cuando llegamos a didChange
es diferente de lo que se anticipó. Esto puede dañar las aplicaciones de algunas personas, pero no afecta a las mías, ya que solo agrego nuevos objetos o confirmo sus ubicaciones finales antes de agregarlas.
- (void)addChildrenObject:(BAFinancialItem *)value {
if ([self.children containsObject:value]) {
return;
}
NSIndexSet * indexSet = [NSIndexSet indexSetWithIndex:self.children.count];
[self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexSet forKey:ChildrenKey];
[[self primitiveValueForKey:ChildrenKey] addObject:value];
[self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexSet forKey:ChildrenKey];
}
- (void)removeChildrenObject:(BAFinancialItem *)value {
if (![self.children containsObject:value]) {
return;
}
NSIndexSet * indexSet = [NSIndexSet indexSetWithIndex:[self.children indexOfObject:value]];
[self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexSet forKey:ChildrenKey];
[[self primitiveValueForKey:ChildrenKey] removeObject:value];
[self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexSet forKey:ChildrenKey];
}
- (void)addChildren:(NSOrderedSet *)values {
if ([values isSubsetOfOrderedSet:self.children]) {
return;
}
NSIndexSet * indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(self.children.count, values.count)];
[self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexSet forKey:ChildrenKey];
[[self primitiveValueForKey:ChildrenKey] unionOrderedSet:values];
[self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexSet forKey:ChildrenKey];
}
- (void)removeChildren:(NSOrderedSet *)values {
if (![self.children intersectsOrderedSet:values]) {
return;
}
NSIndexSet * indexSet = [self.children indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [values containsObject:obj];
}];
[self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexSet forKey:ChildrenKey];
[[self primitiveValueForKey:ChildrenKey] minusOrderedSet:values];
[self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexSet forKey:ChildrenKey];
}
Por supuesto, hay una solución más fácil. es como sigue
- (void)addChildrenObject:(BAFinancialItem *)value {
if ([self.children containsObject:value]) {
return;
}
[self insertObject:value inChildrenAtIndex:self.children.count];
}
- (void)removeChildrenObject:(BAFinancialItem *)value {
if (![self.children containsObject:value]) {
return;
}
[self removeObjectFromChildrenAtIndex:[self.children indexOfObject:value]];
}
- (void)addChildren:(NSOrderedSet *)values {
if ([values isSubsetOfOrderedSet:self.children]) {
return;
}
[self insertChildren:values atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(self.children.count, values.count)]];
}
- (void)removeChildren:(NSOrderedSet *)values {
if (![self.children intersectsOrderedSet:values]) {
return;
}
[self removeChildrenAtIndexes:[self.children indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [values containsObject:obj];
}]];
}
He tenido el mismo problema, pero solo cuando probé algo diferente a lo que había estado haciendo. No puedo ver el código para el artículo secundario, pero asumiré que tiene un enlace inverso al elemento. Llamemos a este enlace reveres, "parentItem", entonces la solución más fácil es esta:
Item *item = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:self.managedObjectContext];
item.name = @"FirstItem";
SubItem *subItem = [NSEntityDescription insertNewObjectForEntityForName:@"SubItem" inManagedObjectContext:self.managedObjectContext];
//[item addSubitemsObject:subItem];
subItem.parentItem = item;
El efecto es que hace uso del propio código de Apple y es simple y limpio. Además, el conjunto se agrega automáticamente a, y todos los observadores se actualizan. No hay problema.
Parece que si se vincula al padre con el hijo configurando al padre con el hijo y no al revés, funciona sin fallar.
Así que si lo haces:
[child setParent:parent]
en lugar de
[parent setChildObects:child]
Debería funcionar, al menos funciona en iOS 7 y no tuvo ningún problema con la relación.
Personalmente, acabo de reemplazar las llamadas a los métodos generados por CoreData con llamadas directas al método como se describe en otra solución por @Stephan:
NSMutableOrderedSet* tempSet = [self mutableOrderedSetValueForKey:@"subitems"];
[tempSet addObject:value];
[tempSet addObject:value];
Esto elimina la necesidad de categorías que luego podrían entrar en conflicto con una solución de Apple al código generado cuando se solucione el error.
¡Esto tiene la ventaja adicional de ser la forma oficial de hacerlo!
Recibí el mismo error, la solución @LeeIII funcionó para mí (¡gracias!). Sugiero modificarlo ligeramente:
- use la categoría object-c para almacenar el nuevo método (por lo que no perderemos nuestro método si se genera nuevamente el artículo)
- Comprueba si ya tenemos set mutable.
Contenido del Item+category.m
:
#import "Item+category.h"
@implementation Item (category)
- (void)addSubitemsObject:(SubItem *)value {
if ([self.subitems isKindOfClass:[NSMutableOrderedSet class]]) {
[(NSMutableOrderedSet *)self.subitems addObject:value];
} else {
NSMutableOrderedSet* tempSet = [NSMutableOrderedSet orderedSetWithOrderedSet:self.subitems];
[tempSet addObject:value];
self.subitems = tempSet;
}
}
@end
Reproducí su configuración tanto con su modelo de datos como con uno propio con diferentes nombres. Tengo el mismo error en ambos casos.
Parece un error en el código autogenerado de Apple.
Sí, este es definitivamente un error de Core Data. Escribí una solución basada en ObjC-Runtime hace un tiempo, pero en ese momento pensé que sería reparado pronto. De todos modos, no tuve tanta suerte, así que lo KCOrderedAccessorFix en GitHub como KCOrderedAccessorFix . Resuelva el problema en todas sus entidades:
[managedObjectModel kc_generateOrderedSetAccessors];
Una entidad en particular:
[managedObjectModel kc_generateOrderedSetAccessorsForEntity:entity];
O solo para una relación:
[managedObjectModel kc_generateOrderedSetAccessorsForRelationship:relationship];
Si está utilizando mogenerator, entonces en lugar de
[parentObject add<Child>sObject:childObject];
simplemente use:
[[parent object <child>sSet] addObject:childObject];
Simplemente me equivoqué de este problema y lo resolví utilizando una implementación mucho más sencilla que las otras que se describen aquí. Simplemente hago uso de los métodos disponibles en NSManagedObject
para tratar las relaciones cuando no NSManagedObject
subclases.
Una implementación de ejemplo para insertar una entidad en una relación NSOrderedSet
se vería así:
- (void)addAddress:(Address *)address
{
if ([self.addresses containsObject:address]) {
return;
}
// Use NSManagedObject''s methods for inserting an object
[[self mutableOrderedSetValueForKey:@"addresses"] addObject:address];
}
Esto funciona perfectamente, y es lo que estaba usando antes de pasar a NSManagedObject
subclases NSManagedObject
.
Apple docs To Many Relations dice: debes acceder al conjunto mutable de proxy o al conjunto ordenado usando
NSMutableOrderedSet * set = [managedObject mutableOrderedSetValueForKey:@"toManyRelation"];
La modificación de este conjunto agregará o eliminará relaciones con su objeto administrado. Accediendo al conjunto ordenado mutable usando el descriptor de acceso ya sea con [] o. La notación es incorrecta y fallará.
Acabo de recibir el problema en Swift (Xcode 6.1.1).
La respuesta fue NO CODIGA NINGÚN MÉTODO O COSAS ADICIONALES en sus subclases de Objeto Gestionado NS. Creo que es un error del compilador. Muy extraño bicho ..
Espero eso ayude ..
Mejor versión de la respuesta correcta en SWIFT.
var tempSet = NSMutableOrderedSet()
if parent!.subItems != nil {
tempSet = NSMutableOrderedSet(orderedSet: parent!.subItems!)
}
tempSet.add(newItem)
parent!.subItems = tempSet
Robert
Estoy de acuerdo en que su respuesta funcionará para esto, pero tenga en cuenta que ya existe un método creado automáticamente para agregar un conjunto completo de valores a una relación. La Documentación de Apple ( como se ve aquí en la sección "Relaciones de muchos a muchos" o here en la sección "Métodos de acceso a relaciones personalizados a muchos") los implementa de esta manera
- (void)addEmployees:(NSSet *)value
{
[self willChangeValueForKey:@"employees"
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:value];
[[self primitiveEmployees] unionSet:value];
[self didChangeValueForKey:@"employees"
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:value];
}
- (void)removeEmployees:(NSSet *)value
{
[self willChangeValueForKey:@"employees"
withSetMutation:NSKeyValueMinusSetMutation
usingObjects:value];
[[self primitiveEmployees] minusSet:value];
[self didChangeValueForKey:@"employees"
withSetMutation:NSKeyValueMinusSetMutation
usingObjects:value];
}
Puede compilar fácilmente su conjunto de relaciones fuera de los datos centrales y luego agregarlos todos a la vez utilizando este método. Podría ser menos feo que el método que sugirió;)
Descubrí que usar el método de LeeIII funcionó, pero en el análisis de perfiles descubrí que era drásticamente lento. Tomó 15 segundos analizar 1000 elementos. Comentando el código para agregar la relación se convirtió 15 segundos en 2 segundos.
Mi solución (que es más rápida pero mucho más fea) implica crear una matriz mutable temporal y luego copiarla en el conjunto ordenado cuando se realiza todo el análisis. (esto es solo una ganancia de rendimiento si va a agregar muchas relaciones).
@property (nonatomic, retain) NSMutableArray* tempItems;
....
@synthesize tempItems = _tempItems;
....
- (void) addItemsObject:(KDItem *)value
{
if (!_tempItems) {
self.tempItems = [NSMutableArray arrayWithCapacity:500];
}
[_tempItems addObject:value];
}
// Call this when you have added all the relationships
- (void) commitRelationships
{
if (_tempItems) {
self.items = [NSOrderedSet orderedSetWithArray:self.tempItems];
self.tempItems = nil;
}
}
Espero que esto ayude a alguien mas!
Encontré esta pregunta buscando el mensaje de error en Google, y solo quería señalar que me encontré con este error de una manera ligeramente diferente (sin usar conjuntos ordenados). Esta no es una respuesta a la pregunta dada, pero la estoy publicando aquí en caso de que sea útil para cualquier otra persona que se encuentre con esta pregunta durante la búsqueda.
Estaba agregando una nueva versión del modelo y agregue algunas relaciones a los modelos existentes, y definí los métodos para agregar * Objetos en el archivo de encabezado. Cuando traté de llamarlos, recibí el error anterior.
Después de revisar mis modelos, me di cuenta de que me había olvidado estúpidamente de marcar la casilla de verificación "To-Many Relationship".
Entonces, si te encuentras con esto y no estás usando conjuntos ordenados, revisa dos veces tu modelo.
Estoy bastante seguro de que finalmente se solucionó en iOS 10 beta 6 !
He encontrado una solución para este error que funciona para mí. Solo sustituyo esto:
[item addSubitemsObject:subItem];
con este:
item.subitemsObject = subItem;
Tengo la misma situación con un elemento llamado "señales" en lugar de "subelementos". La solución con tempset funciona en mis pruebas. Además, tuve un problema con el método removeSignals: Esta anulación parece funcionar:
- (void)removeSignals:(NSOrderedSet *)values {
NSMutableOrderedSet* tempset = [NSMutableOrderedSet orderedSetWithOrderedSet:self.signals];
for (Signal* aSignal in values) {
[tempset removeObject:aSignal];
}
self.signals = tempset;
}
Si hay una mejor manera de hacerlo, hágamelo saber. La entrada de mis valores nunca es más de 10 -20 elementos, por lo que el rendimiento no es un problema, no obstante, señale cualquier cosa relevante.
Gracias,
Damien