Зависание / сбой приложения после добавления NSSet сущностей со связями - PullRequest
1 голос
/ 06 декабря 2010

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

Модель данных

Примечание: я упростил код и модельнасколько я могу.

В моей модели данных Core есть 3 объекта.

  • Merchant (может иметь много Branch es, может иметь много Sector s)
  • Sector (может иметь много Merchant s)
  • Branch (может иметь один Merchant)

Данные загружены(в формате JSON) в приложение.Каждый Merchant повторяется по извлеченным секторам, если сектор существует, он выбирается и добавляется в NSMutableArray.

...
//Iterating through Merchants
...
for(NSDictionary *sector in sectors) {
    NSLog(@"\tfetch sectors ID %@", [sector objectForKey:@"sector_id"]);

    NSPredicate *sectorPredicate = [NSPredicate predicateWithFormat:@"%K == %d", @"sectorID", [[sector objectForKey:@"sector_id"] integerValue]];
    [sectorRequest setPredicate:sectorPredicate];

    NSArray *existingSector = [self.managedObjectContext executeFetchRequest:sectorRequest error:&error];

    if(!error && [existingSector count] == 1) {
        NSLog(@"\tfound sector");
    [merchantSectors addObject:[existingSector objectAtIndex:0]];
    }
    else {
        NSLog(@"\tcreate a new sector");

        //Create a new sector
        Sector *newSector = [[Sector alloc] initWithEntity:sectorEntity insertIntoManagedObjectContext:self.managedObjectContext];
        newSector.sectorID = [NSNumber numberWithInteger:[[sector objectForKey:@"sector_id"] integerValue]];
        newSector.name = [sector objectForKey:@"name"];

        [merchantSectors addObject:newSector];

        [newSector release]; newSector = nil;
    }
}

[sectorRequest release]; sectorRequest = nil;

NSLog(@"\tadd sectors to merchant");
[currentMerchant addSector:merchantSectors]; //<---- crash and hang

Приложение будет зависать по адресу:

 [currentMerchant addSector:merchantSectors];

или иногда выдает исключение:

*** Terminating app due to uncaught exception \
'NSInternalInconsistencyException', reason: \ 
'-[__NSCFSet addObject:]: mutating method sent to immutable object'

Код синтаксического анализа Branch практически идентичен, но никогда не имеет этих проблем, или приложение зависнет или завершится сбоем, прежде чем оно станет проблемой (??).

Если приложение удаляется и переустанавливается, код будет работать нормально, возможно ли, что существующие идентичные отношения вызывают эту проблему?

Редактировать: Анализ JSON вызывается с помощьюNSInvocationOperation, поэтому, когда он зависает, интерфейс остается отзывчивым.Аварийная версия убивает приложение.

Редактировать 2: Merchant.h и Merchant.m

Merchant.h

#import <CoreData/CoreData.h>

@class Branch;
@class Sector;

@interface Merchant :  NSManagedObject  
{
}

@property (nonatomic, retain) NSString * street;
@property (nonatomic, retain) NSString * locality;
@property (nonatomic, retain) NSString * city;
@property (nonatomic, retain) NSNumber * merchantID;
@property (nonatomic, retain) NSString * postcode;
@property (nonatomic, retain) NSString * property;
@property (nonatomic, retain) NSString * organisation;
@property (nonatomic, retain) NSDate * expires;
@property (nonatomic, retain) NSSet * Branch;
@property (nonatomic, retain) NSSet* Sector;

@end


@interface Merchant (CoreDataGeneratedAccessors)
- (void)addBranchObject:(Branch *)value;
- (void)removeBranchObject:(Branch *)value;
- (void)addBranch:(NSSet *)value;
- (void)removeBranch:(NSSet *)value;
- (void)addSectorObject:(Sector *)value;
- (void)removeSectorObject:(Sector *)value;
- (void)addSector:(NSSet *)value;
- (void)removeSector:(NSSet *)value;

@end

Merchant.m

#import "Merchant.h"
#import "Branch.h"

@implementation Merchant 

@dynamic street;
@dynamic locality;
@dynamic city;
@dynamic merchantID;
@dynamic postcode;
@dynamic property;
@dynamic organisation;
@dynamic expires;
@dynamic Branch;
@dynamic Sector;

@end

1 Ответ

1 голос
/ 25 января 2011

Попробуйте добавить секторы в Merchant один за другим, используя автоматически сгенерированные методы CoreData add<Key>Object: и remove<Key>Object: (как описано в Пользовательские методы доступа ко многим отношениям )

for(NSDictionary *sector in sectors) {
    NSPredicate *sectorPredicate = [NSPredicate predicateWithFormat:@"%K == %d", @"sectorID", [[sector objectForKey:@"sector_id"] integerValue]];
    [sectorRequest setPredicate:sectorPredicate];

    NSArray *existingSector = [self.managedObjectContext executeFetchRequest:sectorRequest error:&error];

    if(!error && [existingSector count] == 1) 
    {
        [currentMerchant addSectorObject:[existingSector lastObject]];
    }
    else 
    {
        Sector *newSector = [[Sector alloc] initWithEntity:sectorEntity insertIntoManagedObjectContext:self.managedObjectContext];
        newSector.sectorID = [NSNumber numberWithInteger:[[sector objectForKey:@"sector_id"] integerValue]];
        newSector.name = [sector objectForKey:@"name"];

        [currentMerchant addSectorObject:newSector];

        [newSector release];
    }
}

Или вы можете получить изменяемый прокси-объект, содержащий сектора currentMerchants, через mutableSetValueForKey: и добавить к нему сектора:

NSMutableSet *merchantSectors = [currentMerchant mutableSetValueForKey:@"sector"];
for(NSDictionary *sector in sectors) {
    NSPredicate *sectorPredicate = [NSPredicate predicateWithFormat:@"%K == %d", @"sectorID", [[sector objectForKey:@"sector_id"] integerValue]];
    [sectorRequest setPredicate:sectorPredicate];

    NSArray *existingSector = [self.managedObjectContext executeFetchRequest:sectorRequest error:&error];

    if(!error && [existingSector count] == 1) 
    {
        [merchantSectors addObject:[existingSector lastObject]];
    }
    else 
    {
        Sector *newSector = [[Sector alloc] initWithEntity:sectorEntity insertIntoManagedObjectContext:self.managedObjectContext];
        newSector.sectorID = [NSNumber numberWithInteger:[[sector objectForKey:@"sector_id"] integerValue]];
        newSector.name = [sector objectForKey:@"name"];

        [merchantSectors addObject:newSector];

        [newSector release];
    }
}

В любом случае, для удобства, лучше использовать строчное sectors имя для объекта Mecrhant для to-многие отношения с сущностью Sector: строчные буквы не должны быть неоднозначными с Sector именем класса, а с s at и, чтобы быть уверенным, что методы получения для этого свойства возвращают несколько объектов.

...