No meu aplicativo Lion, eu tenho este modelo de dados:
O relacionamento subitems
interno Item
é ordenado .
Xcode 4.1 (compilação 4B110) criou para mim o arquivo Item.h
, Item.m
, SubItem.h
e SubItem.h
.
Aqui está o conteúdo (gerado automaticamente) 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
E aqui está o conteúdo (gerado automaticamente) de Item.m
:
#import "Item.h"
#import "SubItem.h"
@implementation Item
@dynamic name;
@dynamic subitems;
@end
Como você pode ver, a classe Item
oferece um método chamado addSubitemsObject:
. Infelizmente, ao tentar usá-lo desta maneira:
Item *item = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:self.managedObjectContext];
item.name = @"FirstItem";
SubItem *subItem = [NSEntityDescription insertNewObjectForEntityForName:@"SubItem" inManagedObjectContext:self.managedObjectContext];
[item addSubitemsObject:subItem];
este erro aparece:
2011-09-12 10:28:45.236 Test[2002:707] *** -[NSSet intersectsSet:]: set argument is not an NSSet
Pode me ajudar?
Atualizar:
Após apenas 1.787 dias do meu relatório de erros, hoje (1 de agosto de 2016) a Apple me escreveu o seguinte: "Verifique este problema com a versão beta mais recente do iOS 10 e atualize seu relatório de erros em bugreport.apple.com com seus resultados." . Espero que este seja o momento certo :)
mutableOrderedSetValueForKey:
)Respostas:
Reproduzi sua configuração com seu modelo de dados e um com meus nomes diferentes. Eu recebi o mesmo erro nos dois casos.
Parece um bug no código gerado automaticamente pela Apple.
fonte
Concordo que pode haver um erro aqui. Modifiquei a implementação do setter set add para acrescentar corretamente a um NSMutableOrderedSet.
A reatribuição do conjunto como self.subitems garantirá que as notificações Will / DidChangeValue sejam enviadas.
fonte
Decidi melhorar a solução implementando todos os métodos necessários:
fonte
willChangeValueForKey:withSetMutation:usingObjects
que você evitou com sucesso. Depois disso, basta usar[[self primitiveValueForKey:ChildrenKey] unionOrderedSet:values]
ou[[self primitiveValueForKey:ChildrenKey] minusOrderedSet:values]
conforme apropriado. Veja minha resposta para detalhes.Sim, esse é definitivamente um bug do Core Data. Escrevi uma correção baseada em ObjC-Runtime há um tempo, mas na época achei que seria corrigida em breve. De qualquer forma, não tive essa sorte, então eu publiquei no GitHub como KCOrderedAccessorFix . Solução alternativa do problema em todas as suas entidades:
Uma entidade em particular:
Ou apenas para um relacionamento:
fonte
- (BOOL)kc_needsOrderedSetAccessorFix;
ou algo que verifique a versão do Foundation / iOS.objc_msg_send
)Em vez de fazer uma cópia, sugiro usar o acessador no NSObject para obter acesso ao NSMutableOrderedSet dos relacionamentos.
por exemplo, as Notas da versão do Core Data para iOS v5.0 se referem a isso.
Em um teste curto, funcionou no meu aplicativo.
fonte
NSStringFromSelector(@selector(subitems))
embora :)Eu rastreei o bug. Isso ocorre em
willChangeValueForKey:withSetMutation:usingObjects:
.Essa ligação desencadeia uma cadeia de notificações que podem ser difíceis de rastrear e, é claro, alterações em um atendedor podem ter implicações em outro, o que suspeito é o motivo pelo qual a Apple não fez nada.
No entanto, está tudo bem no Set e são apenas as operações do Set em um OrderedSet que funcionam mal. Isso significa que existem apenas quatro métodos que precisam ser alterados. Portanto, tudo o que fiz foi converter as operações Set em suas operações Array equivalentes. Eles funcionam perfeitamente e com sobrecarga mínima (mas necessária).
Em um nível crítico, esta solução sofre de uma falha crítica; se você estiver adicionando objetos e um dos objetos já existir, ele não será adicionado ou movido para o final da lista ordenada (não sei qual). Em ambos os casos, o índice ordenado esperado do objeto no momento em que chegamos
didChange
é diferente do que era antecipado. Isso pode quebrar os aplicativos de algumas pessoas, mas não afeta os meus, pois apenas adiciono novos objetos ou confirmo seus locais finais antes de adicioná-los.Claro, existe uma solução mais fácil. é o seguinte;
fonte
Os documentos da Apple Para Muitas Relações dizem: você deve acessar o conjunto mutável de proxy ou o conjunto ordenado usando
A modificação deste conjunto adicionará ou removerá relações ao seu objeto gerenciado. Acessando o conjunto ordenado mutável usando o acessador, com [] ou. notação está errada e falhará.
fonte
Recebeu o mesmo erro, a solução @LeeIII funcionou para mim (obrigado!). Sugiro modificá-lo ligeiramente:
Conteúdo de
Item+category.m
:fonte
Se você estiver usando o mogenerator, em vez de
basta usar:
fonte
mogenerator
mas ainda tenho o bug.Pessoalmente, acabei de substituir as chamadas para os métodos gerados pelo CoreData por chamadas diretas ao método, conforme descrito em outra solução por @Stephan:
Isso elimina a necessidade de categorias que posteriormente possam entrar em conflito com uma solução da Apple para o código gerado quando o bug for corrigido.
Isso tem a vantagem adicional de ser a maneira oficial de fazê-lo!
fonte
addObject:
chamado duas vezes?Parece que se você vincular o pai ao filho, definindo o pai para o filho e não o contrário, funcionará sem travar.
Então, se você fizer:
ao invés de
Deve funcionar, pelo menos funciona no iOS 7 e não teve problemas com o relacionamento.
fonte
Eu tive o mesmo problema, mas apenas quando tentei algo diferente do que estava fazendo. Não consigo ver o código do subItem, mas assumirei que ele possui um link reverso para o item. Vamos chamar esse link de reverência, "parentItem", então a solução mais fácil é a seguinte:
O efeito é que ele usa o próprio código da apple e é simples e limpo. Além disso, o conjunto é adicionado automaticamente e todos os observadores são atualizados. Sem problemas.
fonte
Acabei de entrar em conflito com esse problema e resolvi-o usando uma implementação muito mais simples do que as outras descritas aqui. Simplesmente uso os métodos disponíveis
NSManagedObject
para lidar com relacionamentos quando não estou usando subclasses.Um exemplo de implementação para inserir uma entidade em um
NSOrderedSet
relacionamento ficaria assim:Isso funciona perfeitamente e é o que eu estava usando antes de passar para as
NSManagedObject
subclasses.fonte
Este problema ocorreu ao migrar um projeto do Objective-C para o Swift 2 com o XCode 7 . Esse projeto funcionou e por um bom motivo: eu estava usando o MOGenerator que tinha métodos de substituição para corrigir esse bug. Mas nem todos os métodos exigem uma substituição.
Então, aqui está a solução completa com uma classe de exemplo, contando com acessadores padrão o máximo possível.
Digamos que tenhamos uma lista com itens solicitados
Primeiro, uma vitória rápida, se você tiver um relacionamento de um para muitos, o mais fácil é:
ao invés de
Agora, se isso não for uma opção , eis o que você pode fazer:
Obviamente, se você estiver usando o Objective-C, poderá fazer exatamente a mesma coisa, pois foi aí que eu tive a ideia em primeiro lugar :)
fonte
Leelll, você tem certeza de que, após a configuração personalizada dos valores NSMutableOrderedSet armazenados nesse conjunto, serão salvos no banco de dados corretamente pelo CoreData? Não verifiquei isso, mas parece que o CoreData não sabe nada sobre NSOrderedSet e espera que o NSSet seja um contêiner de relacionamento com muitos.
fonte
Acho que todo mundo está perdendo o problema real. Não está nos métodos do acessador, mas no fato de
NSOrderedSet
não ser uma subclasse deNSSet
. Portanto, quando-interSectsSet:
é chamado com um conjunto ordenado como argumento, ele falha.falha com
*** -[NSSet intersectsSet:]: set argument is not an NSSet
Parece que a correção é alterar a implementação dos operadores de conjunto para que eles manipulem os tipos de maneira transparente. Não há razão para que a
-intersectsSet:
deva funcionar com um conjunto ordenado ou não ordenado.A exceção acontece na notificação de alteração. Presumivelmente no código que lida com o relacionamento inverso. Como isso só acontece se eu estabelecer um relacionamento inverso.
O seguinte fez o truque para mim
fonte
Acabei de receber o problema no Swift (Xcode 6.1.1).
A resposta foi NÃO CODIFICAR QUALQUER MÉTODO OU COISA ADICIONAL nas subclasses do NSManagedObject. Eu acho que é um erro do compilador. Bug muito estranho ..
Espero que ajude ..
fonte
Resolvi esse problema definindo o inverso como No Inverse, não sei por que, talvez exista o Apple Bug.
fonte
Eu tenho a mesma situação com um item chamado "sinais" em vez de "subitens". A solução com tempset funciona nos meus testes. Além disso, tive um problema com o método removeSignals:. Essa substituição parece funcionar:
Se houver uma maneira melhor de fazer isso, entre em contato. Minha entrada de valores nunca é superior a 10 a 20 itens, portanto o desempenho não é uma grande preocupação - no entanto, aponte algo relevante.
Obrigado,
Damien
fonte
Encontrei essa pergunta pesquisando a mensagem de erro no Google e só queria salientar que encontrei esse erro de uma maneira ligeiramente diferente (sem usar conjuntos ordenados). Essa não é uma resposta para a pergunta em questão, mas estou postando aqui para o caso de ser útil para qualquer pessoa que se deparar com essa pergunta enquanto estiver pesquisando.
Eu estava adicionando uma nova versão do modelo, adicionei alguns relacionamentos aos modelos existentes e defini os métodos add * Object no arquivo de cabeçalho. Quando tentei ligar para eles, recebi o erro acima.
Depois de revisar meus modelos, percebi que havia me esquecido estupidamente de marcar a caixa de seleção "Relacionamento com muitos".
Portanto, se você estiver enfrentando isso e não estiver usando conjuntos ordenados, verifique seu modelo.
fonte
Encontrei uma correção para esse bug que funciona para mim. Eu apenas substituo isso:
com isso:
fonte
Melhor versão da resposta correta no SWIFT
fonte
Descobri que o método de LeeIII funcionava, mas na criação de perfis, era drasticamente lento. Demorou 15 segundos para analisar 1000 itens. Comentar o código para adicionar o relacionamento transformou 15 segundos em 2 segundos.
Minha solução alternativa (que é mais rápida, mas muito mais feia) envolve a criação de uma matriz mutável temporária e a cópia no conjunto ordenado quando toda a análise é concluída. (isso é apenas uma vitória no desempenho se você deseja adicionar muitos relacionamentos).
Espero que isso ajude outra pessoa!
fonte
Robert,
Concordo que sua resposta funcionará para isso, mas lembre-se de que já existe um método criado automaticamente para adicionar todo um conjunto de valores a um relacionamento. A documentação da Apple ( como pode ser vista aqui na seção "Relacionamentos para muitos" ou aqui na seção "Métodos personalizados de acessor de relacionamento para muitos") os implementa da seguinte maneira:
Você pode compilar facilmente seu conjunto de relacionamentos fora dos dados principais e adicioná-los todos de uma vez usando esse método. Pode ser menos feio do que o método que você sugeriu;)
fonte
Tenho certeza de que finalmente foi corrigido no iOS 10 beta 6 !
fonte