Programing

NSOrderedSet 생성 접근 자에서 예외가 발생했습니다.

lottogame 2020. 2. 28. 18:36
반응형

NSOrderedSet 생성 접근 자에서 예외가 발생했습니다.


Lion 앱에는 다음과 같은 데이터 모델이 있습니다.

여기에 이미지 설명을 입력하십시오

subitems내부 관계 Item 는 주문 됩니다.

엑스 코드 4.1 (빌드 4B110)는 나를 위해 파일을 만들었습니다 Item.h, Item.m, SubItem.hSubItem.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

도와주세요?

최신 정보:

Apple은 오늘 (2016 년 8 월 1 일) 내 버그 보고서에서 1,787 일 만에 다음과 같이 썼습니다. "최신 iOS 10 베타 빌드로이 문제를 확인하고 bugreport.apple.com에서 버그 보고서를 결과로 업데이트하십시오." . 이것이 올바른 시간이 되길 바랍니다 :)


데이터 모델과 다른 이름을 가진 자체 모델 중 하나를 사용하여 설정을 재현했습니다. 두 경우 모두 같은 오류가 발생했습니다.

Apple의 자동 생성 코드의 버그처럼 보입니다.


여기에 버그가있을 수 있음에 동의합니다. NSMutableOrderedSet에 올바르게 추가하기 위해 add object setter의 구현을 수정했습니다.

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

집합을 self.subitems로 다시 할당하면 Will / DidChangeValue 알림이 전송됩니다.


필요한 모든 방법을 구현하여 솔루션을 개선하기로 결정했습니다.

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];
    }
}

예, 이것은 확실히 핵심 데이터 버그입니다. 나는 ObjC- 런타임 기반 수정을 얼마 전에 작성했지만 그 시점에서 곧 수정 될 것이라고 생각했습니다. 어쨌든 그런 운이 없기 때문에 GitHub에 KCOrderedAccessorFix 로 게시했습니다 . 모든 엔티티에 대한 문제를 해결하십시오.

[managedObjectModel kc_generateOrderedSetAccessors];

특히 하나의 실체 :

[managedObjectModel kc_generateOrderedSetAccessorsForEntity:entity];

아니면 하나의 관계 만 :

[managedObjectModel kc_generateOrderedSetAccessorsForRelationship:relationship];

복사하는 대신 NSObject에서 접근자를 사용하여 관계의 NSMutableOrderedSet에 액세스하는 것이 좋습니다.

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

예를 들어 iOS v5.0 용 Core Data Release Notes 가이를 참조합니다.

짧은 테스트에서 그것은 내 응용 프로그램에서 작동했습니다.


버그를 추적했습니다. 에서 발생합니다 willChangeValueForKey:withSetMutation:usingObjects:.

이 전화는 추적하기 어려울 수있는 일련의 알림을 설정하며 물론 한 응답자에 대한 변경 사항이 다른 응답자에게 영향을 줄 수 있으므로 Apple이 아무런 조치를 취하지 않은 것 같습니다.

그러나 Set에서는 문제가없고 OrderedSet에 대한 Set 작업 만 가능합니다. 즉, 변경해야 할 네 가지 방법 만 있습니다. 따라서 Set 작업을 동등한 Array 작업으로 변환하기 만했습니다. 이것들은 완벽하고 최소한의 (필요한) 오버 헤드로 작동합니다.

중요한 수준에서이 솔루션은 하나의 중요한 결함으로 인해 어려움을 겪습니다. 객체를 추가하고 있고 객체 중 하나가 이미 존재하는 경우 객체가 추가되거나 순서가 지정된 목록의 뒷면으로 이동되지 않습니다 (어떤 것을 모르겠습니다). 두 경우 모두, 우리가 도착할 때까지 개체의 예상 순서 인덱스 didChange는 예상과 다릅니다. 이것은 일부 사람들의 앱을 망가뜨릴 수 있지만 새로운 객체 만 추가하거나 추가하기 전에 최종 위치를 확인하기 때문에 영향을 미치지 않습니다.

- (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];
}

물론 더 쉬운 해결책이 있습니다. 다음과 같습니다.

- (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];
    }]];
}

많은 관계로 애플 문서는 말한다 : 프록시 변경 가능한 설정에 액세스해야하거나 사용하여 설정 순서화

NSMutableOrderedSet * set = [managedObject mutableOrderedSetValueForKey:@"toManyRelation"];

이 세트를 수정하면 관리 대상 객체에 관계가 추가되거나 제거됩니다. [] 또는을 사용하여 액세서를 사용하여 변경 가능 순서 ​​세트에 액세스합니다. 표기법이 잘못되어 실패합니다.


@LeeIII 솔루션이 동일한 오류를 받았습니다 (감사합니다!). 약간 수정하는 것이 좋습니다.

  • objective-c category를 사용하여 새 메소드를 저장하십시오. 따라서 Item이 다시 생성되면 메소드를 잃지 않습니다.
  • 이미 변경 가능한 세트가 있는지 확인하십시오

내용 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

mogenerator를 사용하는 경우 대신

[parentObject add<Child>sObject:childObject];

간단히 사용하십시오 :

[[parent object <child>sSet] addObject:childObject];

개인적으로 @Stephan의 다른 솔루션에 요약 된대로 CoreData 생성 메소드에 대한 호출을 메소드에 대한 직접 호출로 대체했습니다.

NSMutableOrderedSet* tempSet = [self mutableOrderedSetValueForKey:@"subitems"];
      [tempSet addObject:value];
[tempSet addObject:value];

따라서 버그가 수정되면 나중에 Apple에서 생성 된 코드로 솔루션과 충돌 할 수있는 범주가 필요하지 않습니다.

여기에는 공식적인 방법이 추가되었습니다!


부모를 자식으로 설정하여 부모를 자식과 연결하면 다른 방법으로 충돌하지 않고 작동하는 것처럼 보입니다.

그래서 당신이 할 경우 :

[child setParent:parent]

대신에

[parent setChildObects:child]

그것은 적어도 iOS 7에서 작동하며 관계에 아무런 문제가 없었습니다.


나는 같은 문제가 있었지만, 내가하고있는 것과 다른 것을 시도했을 때만. 하위 항목의 코드를 볼 수 없지만 항목에 대한 역방향 링크가 있다고 가정합니다. 이 링크를 "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;

그 결과 Apple 자체 코드를 사용하며 간단하고 깨끗합니다. 또한 세트가 자동으로 추가되고 모든 옵저버가 업데이트됩니다. 문제 없어요.


방금이 문제를 파기하고 여기에 설명 된 다른 것보다 훨씬 간단한 구현을 사용하여 해결했습니다. 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하위 클래스 로 이동하기 전에 사용한 것 입니다.


XCode 7을 사용 하여 Objective-C에서 Swift 2프로젝트를 마이그레이션하는 동안이 문제가 발생했습니다 . 그 프로젝트는 효과가 있었으며 그만한 이유가 있습니다.이 버그를 고치기위한 대체 방법이있는 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를 사용하는 경우 처음부터 아이디어를 얻었으므로 정확히 동일한 작업을 수행 할 수 있습니다. :)


여기에 버그가 있음에 동의합니다. NSMutableOrderedSet에 올바르게 추가하기 위해 add 객체> setter의 구현을 수정했습니다.

- (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을 기대하는 것처럼 보입니다.


나는 모든 사람이 실제 문제를 놓치고 있다고 생각합니다. 접근 자 메서드 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

방금 Swift (Xcode 6.1.1)에서 문제가 발생했습니다.

답은 NSManagedObject 서브 클래스에 어떤 방법이나 추가 사항을 코딩하지 않았습니다 . 나는 그것이 컴파일러 실수라고 생각합니다. 매우 이상한 버그 ..

그것이 도움이되기를 바랍니다 ..


나는 Inverse를 No Inverse로 설정 하여이 문제를 해결했습니다. 왜 애플 버그가 있는지 모르겠습니다.여기에 이미지 설명을 입력하십시오


"subitems"대신 "signals"라는 항목과 동일한 상황이 있습니다. tempset이있는 솔루션은 테스트에서 작동합니다. 또한 removeSignals : 메서드에 문제가있었습니다. 이 재정의가 작동하는 것 같습니다.

- (void)removeSignals:(NSOrderedSet *)values {
    NSMutableOrderedSet* tempset = [NSMutableOrderedSet orderedSetWithOrderedSet:self.signals];
    for (Signal* aSignal in values) {
        [tempset removeObject:aSignal];
    }
    self.signals = tempset;
}

더 좋은 방법이 있으면 알려주세요. 입력 한 값은 10 -20 개를 넘지 않으므로 성능은 큰 문제가되지 않습니다. 그럼에도 불구하고 관련 내용을 알려주십시오.

감사,

다미 엔


오류 메시지에 대한 인터넷 검색을 통해이 질문을 찾았으며 순서가 다른 세트 (사용하지 않는 세트)를 사용하지 않고이 오류가 발생했다는 것을 지적하고 싶었습니다. 이것은 주어진 질문에 대한 답변이 아니지만 검색하는 동안이 질문을 우연히 발견하는 다른 사람에게 도움이되는 경우를 대비하여 여기에 게시하고 있습니다.

새 모델 버전을 추가하고 기존 모델에 관계를 추가하고 헤더 파일에 add * Object 메소드를 직접 정의했습니다. 전화하려고 할 때 위의 오류가 발생했습니다.

내 모델을 검토 한 후에 "To-Many Relationship"체크 박스를 체크하는 것을 멍청하게 잊었다는 것을 깨달았습니다.

따라서이 문제가 발생하고 주문 세트를 사용하지 않는 경우 모델을 다시 확인하십시오.


이 버그에 대한 수정 사항을 찾았습니다. 나는 이것을 이것을 대체한다 :

[item addSubitemsObject:subItem];

이것으로 :

item.subitemsObject = subItem;

LeeIII의 방법을 사용하는 것이 효과가 있다는 것을 알았지 만 프로파일 링에서 속도가 느리다는 것을 알았습니다. 1000 개의 항목을 파싱하는 데 15 초가 걸렸습니다. 관계를 추가하는 코드를 주석 처리하면 15 초가 2 초로 바뀌 었습니다.

내 해결 방법 (더 빠르지 만 훨씬 추한)은 임시 변경 가능한 배열을 만든 다음 모든 구문 분석이 완료 되면 정렬 된 세트로 복사하는 것입니다. 많은 관계를 추가하려는 경우에만 성능이 향상됩니다.

@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;
    }
}

나는 이것이 다른 누군가를 돕기를 바랍니다!


로버트,

나는 당신의 대답이 이것에 효과적이라고 동의하지만, 관계에 전체 값 세트를 추가하기 위해 자동으로 생성 된 방법이 있음을 명심하십시오. (애플의 문서 여기 본 은 "일대 다 관계"섹션에서 또는 여기에 구현 그들에게이 방법을 "사용자 정의 일대 다 관계 소품 방법"섹션 아래)

- (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];
}

핵심 데이터 외부에서 관계 집합을 쉽게 컴파일 한 다음이 방법을 사용하여 한 번에 모두 추가 할 수 있습니다. 그것은 당신이 제안한 방법보다 추악 할 수 있습니다 .)


나는 그것이 iOS 10 베타 6에서 마침내 고정되어 있다고 확신합니다 !


SWIFT에서 정답의 더 나은 버전

var tempSet = NSMutableOrderedSet()
if parent!.subItems != nil {
    tempSet = NSMutableOrderedSet(orderedSet: parent!.subItems!)
}

tempSet.add(newItem)
parent!.subItems = tempSet

참고 URL : https://stackoverflow.com/questions/7385439/exception-thrown-in-nsorderset-generated-accessors



반응형