我必须解决我认为相关的主要问题,因为它们都出现在同一行代码中。
注意:我尽可能地简化了代码和模型。
我的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
解析代码几乎完全相同但从未出现过这些问题,或者应用程序在成为问题之前会挂起或崩溃(??)。
如果应用程序被删除并重新安装,代码将正常工作,现有的相同关系是否可能导致此问题?
编辑:使用NSInvocationOperation调用JSON的解析,因此当它挂起时,界面保持响应。崩溃版本会杀死应用程序。
编辑2: Merchant.h和Merchant.m
#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
#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
答案 0 :(得分:1)
尝试使用CoreData add<Key>Object:
和remove<Key>Object:
自动生成的方法(如Custom To-Many Relationship Accessor Methods中所述)逐个添加部门到商家
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];
}
}
或者您可以通过mutableSetValueForKey:
检索包含currentMerchants扇区的可变代理对象,并向其添加扇区:
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];
}
}
无论如何,为了方便起见,最好使用Mecrhant实体的小写sectors
名称与Sector实体的多对多关系:小写不要与Sector
类名不明确,并且使用s at和to请确保,此属性的getter方法返回多个对象。