Исключение, генерируемое в сгенерированных средствах доступа NSOrderedSet - PullRequest
363 голосов
/ 12 сентября 2011

В моем приложении Lion у меня есть эта модель данных:

enter image description here

Отношение subitems внутри Item упорядочено .

Xcode 4.1 (build 4B110) создал для меня файл Item.h, Item.m, SubItem.h и SubItem.h.

Вот содержимое (автоматически сгенерированное) 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

А вот содержимое (сгенерированное) Item.m:

#import "Item.h"
#import "SubItem.h"

@implementation Item

@dynamic name;
@dynamic subitems;

@end

Как видите, класс Item предлагает метод с именем addSubitemsObject:. К сожалению, при попытке использовать его таким образом:

Item *item = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:self.managedObjectContext];
item.name = @"FirstItem";

SubItem *subItem = [NSEntityDescription insertNewObjectForEntityForName:@"SubItem" inManagedObjectContext:self.managedObjectContext];

[item addSubitemsObject:subItem];

эта ошибка появляется:

2011-09-12 10:28:45.236 Test[2002:707] *** -[NSSet intersectsSet:]: set argument is not an NSSet

Вы можете мне помочь?

Обновление:

Спустя всего 1787 дней после моего отчета об ошибках, сегодня (1 августа 2016 г.) Apple написала мне следующее: "Пожалуйста, проверьте эту проблему с последней бета-версией iOS 10 и обновите свой отчет об ошибке на bugreport.apple.com с вашими результатами. ". Будем надеяться, что сейчас самое подходящее время:)

Ответы [ 25 ]

5 голосов
/ 02 февраля 2014

Кажется, что если вы связываете родителя с потомком, устанавливая родителя для потомка, а не наоборот, это работает без сбоев.

Итак, если вы сделаете:

[child setParent:parent]

вместо

[parent setChildObects:child]

Это должно работать, по крайней мере, это работает на iOS 7 и не было никаких проблем с отношениями.

3 голосов
/ 16 октября 2013

Я просто заболел этой проблемой и решил ее, используя гораздо более простую реализацию, чем другие, описанные здесь.Я просто использую методы, доступные в NSManagedObject для работы с отношениями, когда не используем подклассы.

Пример реализации для вставки сущности в отношение NSOrderedSet будет выглядеть так:

- (void)addAddress:(Address *)address
{
    if ([self.addresses containsObject:address]) {
        return;
    }
    // Use NSManagedObject's methods for inserting an object
    [[self mutableOrderedSetValueForKey:@"addresses"] addObject:address];
}

Это отлично работает, и это то, что я использовал, прежде чем перейти к NSManagedObject подклассам.

3 голосов
/ 11 января 2012

Я согласен, что здесь может быть ошибка. Я изменил реализацию метода добавления объекта> для правильного добавления к NSMutableOrderedSet.

- (void)addSubitemsObject:(SubItem *)value {
     NSMutableOrderedSet* tempSet = [NSMutableOrderedSet orderedSetWithOrderedSet:self.subitems];
     [tempSet addObject:value];
     self.subitems = tempSet;
}

Переназначение набора для self.subitems обеспечит отправку уведомлений Will / DidChangeValue>.

Leelll, вы уверены, что после такой пользовательской настройки значения NSMutableOrderedSet, сохраненные в этом наборе, будут корректно сохранены в базе данных CoreData? Я не проверял это, но похоже, что CoreData ничего не знает о NSOrderedSet и ожидает, что NSSet будет контейнером связи со многими.

3 голосов
/ 15 августа 2012

У меня была такая же проблема, но только когда я попробовал что-то отличное от того, что я делал. Я не вижу код для подэлемента, но я предполагаю, что он имеет обратную ссылку на элемент. Давайте назовем эту почитаемую ссылку «parentItem», тогда самое простое решение:

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;

Эффект состоит в том, что он использует собственный код яблока, и он прост и чист. Кроме того, набор автоматически добавляется, а все наблюдатели обновляются. Нет проблем.

3 голосов
/ 11 ноября 2015

Эта проблема возникла у меня при переносе проекта с Objective-C на Swift 2 с XCode 7 . Этот проект работал, и по уважительной причине: я использовал MOGenerator, у которого были методы замены, чтобы исправить эту ошибку. Но не все методы требуют замены.

Итак, вот полное решение с примером класса, максимально использующее методы доступа по умолчанию.

Допустим, у нас есть список с заказанными элементами

Сначала быстрый быстрый выигрыш , если у вас отношения один-ко-многим, проще всего просто сделать:

item.list = list

вместо

list.addItemsObject(item)

Теперь, , если это не вариант , вот что вы можете сделать:

// 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

Конечно, если вы используете Objective-C, вы можете сделать то же самое, поскольку именно здесь я и получил идею:)

2 голосов
/ 22 августа 2014

Я думаю, что всем не хватает настоящей проблемы.Дело не в методах доступа, а в том, что NSOrderedSet не является подклассом NSSet.Поэтому, когда -interSectsSet: вызывается с упорядоченным набором в качестве аргумента, происходит сбой.

NSOrderedSet* setA = [NSOrderedSet orderedSetWithObjects:@"A",@"B",@"C",nil];
NSSet* setB = [NSSet setWithObjects:@"C",@"D", nil];

 [setB intersectsSet:setA];

завершается ошибкой с *** -[NSSet intersectsSet:]: set argument is not an NSSet

Похоже, исправление состоит в том, чтобы изменить реализацию операторов набора так,они обрабатывают типы прозрачно.Нет причин, по которым -intersectsSet: должен работать с упорядоченным или неупорядоченным множеством.

Исключение происходит в уведомлении об изменении.Предположительно в коде, который обрабатывает обратные отношения.Так как это происходит только тогда, когда я устанавливаю обратную связь.

Следующее помогло мне

@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
2 голосов
/ 20 июля 2016

Я решил эту проблему, установив обратное значение Нет обратного, я не знаю почему, Может быть, есть ошибка Apple. enter image description here

2 голосов
/ 05 декабря 2014

Я только что получил проблему в Swift (Xcode 6.1.1).

Ответ был НЕ КОДИРУЙТЕ ЛЮБОГО МЕТОДА ИЛИ ДОПОЛНИТЕЛЬНЫХ ВЕЩЕЙ в ваших подклассах NSManagedObject. Я думаю, что это ошибка компилятора. Очень странная ошибка ..

Надеюсь, это поможет ..

1 голос
/ 13 мая 2013

Я нашел исправление для этой ошибки, которое работает для меня.Я просто заменяю это:

[item addSubitemsObject:subItem];

на это:

item.subitemsObject = subItem;
1 голос
/ 17 мая 2013

Я нашел этот вопрос, прибегая к поиску сообщения об ошибке, и просто хотел указать, что столкнулся с этой ошибкой немного по-другому (не используя упорядоченные множества).Это не совсем ответ на заданный вопрос, но я выкладываю его здесь только на тот случай, если он будет полезен всем, кто сталкивается с этим вопросом при поиске.

Я добавлял новую версию модели,и добавил некоторые отношения к существующим моделям, и сам определил методы add * Object в заголовочном файле.Когда я попытался позвонить им, я получил сообщение об ошибке выше.

Просмотрев мои модели, я понял, что тупо забыл поставить галочку напротив «Отношения ко многим».

Так что если выВы сталкиваетесь с этим, и вы не используете упорядоченные наборы, дважды проверьте свою модель.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...