核心数据NSManagedObject isFault在prepareForDeletion中

时间:2013-05-17 09:14:37

标签: objective-c cocoa core-data

我在- prepareForDeletion的{​​{1}}内进行了一些处理。但是,当我尝试访问此类的某些属性时,它们将以NSManagedObject的形式返回给我(即使我知道它们不是nil)。所以我检查我的对象是否有错nil并返回[self isFault]

那么当我在YES内时,如何让对象“无故障”,因为我需要访问一个属性?

PhoneGroup.m(NSManagedObject)

- prepareForDeletion

型号信息:

- (void)prepareForDeletion { [super prepareForDeletion]; NSArray *individuals = [self.individuals allObjects]; // individuals is nil for (int i = 0; i < [individuals count]; i++) { Individual *individual = [individuals objectAtIndex:i]; BOOL individualExistsInOtherGroups = [individual.phoneGroups count] > 1; BOOL individualAddedAsAdditionalContactToReminder = [individual.reminders count] > 0; // We can delete the individual if individual does not exist in other groups and is not added to any reminders if (!individualExistsInOtherGroups && !individualAddedAsAdditionalContactToReminder && ![individual isDeleted]) { [[CoreDataHelper sharedInstance] deleteEntity:individual inManagedObjectContext:self.managedObjectContext]; } } // Post a notification to notify all interested VC so they can refresh the GUI [[NSNotificationCenter defaultCenter] postNotificationName:RMContactDeletedNotification object:self]; DLog(@"Contact deleted notification sent"); } PhoneGroup的反比关系与删除规则无效。

IndividualIndividual的反比关系与删除规则无效。

PhoneGroupContactIndividual s的超类

这是一个可以更好地可视化的图像。

enter image description here

编辑:我在这个问题上做了一些更多的发现

当与PhoneGroup存在关系时,

PhoneGroup似乎只会出错。如果Reminder在被删除时与PhoneGroup没有关系,则错误。

ReminderReminder具有可选的反对多关系,并且删除规则为null。

ContactContact具有可选的反对多关系,并且删除规则为null。

这给了什么?

编辑2:关于此问题的更多信息

我试图丹雪莉的替代解决方案做了取的ReminderŠ的然而均匀的Individual的{​​{1}}(self.managedObjectContext)是NSManagedObjectPhoneGroup里面,这意味着什么?

3 个答案:

答案 0 :(得分:1)

  
    

[self.individuals allObjects]为什么返回nil?

  

修改
在发现您的managedObjectContextnil之后,可以肯定地说您的对象已被其上下文所否定。
这可能是由上下文reset或取消分配引起的,同时您保持对对象的强引用 但是,这并不能解释prepareForDeletion方法中如何发生这种情况 当实时上下文删除对象([context deleteObject:...])时,将调用此方法 这意味着要么手动调用prepareForDeletion[object prepareForDeletion]),要么另一个线程在删除中删除你的上下文。

  
    

注意:鉴于您的对象上设置了有效objectID和实时managedObjectContext,以下代码将有效。

  

然而,我可能有一个解决方法,因为您访问数据的方式效率低下(稍后会解释):

如果您删除的对象(PhoneGroupindividuals关系没有出现故障,CoreData将最终访问商店以确定关系(第一次旅行)。然后,您将有错误作为该关系中包含的对象(N个对象),您的循环将逐个访问它们(N次前往商店)。仍然在循环中,您访问每个对象的关系(2个关系发货,phoneGroupsreminders ==&gt; 2次到商店PER ITEM)。
总结:1 + N + 2 * N = 3 * N + 1次到商店(最坏情况)。

这可以通过更简单的方式实现:
*创建此获取请求:

NSFetchRequest* r = [[NSFetchRequest alloc] initWithEntityName:@"Individual"];
[r setPredicate:[NSPredicate predicateWithFormat:@"%@ IN phoneGroups AND phoneGroups.@count == 1 AND reminders.@count == 0",[self objectID]]];
[r setIncludesPropertyValues:YES];
[r setReturnsObjectsAsFaults:NO];
[r setIncludesPendingChanges:YES];

*现在剩下的就是:

NSManagedObjectContext* context = [self managedObjectContext];
NSArray* individuals = [context executeFetchRequest:r error:NULL];    
for (Individual* individual in individuals) {
    [context deleteObject:individual];
}

这是通过在最坏的情况下单次(1)到商店旅行来完成的,并且由于您不直接依赖于您的关系,只要您的对象具有objectID,这就应该有效。 BR />

<强> Apendix:

当前的实现性能(SQLite调试):

//2013-05-19 21:34:42.700 P[9666:c07] CoreData: sql: SELECT 0, t0.Z_PK FROM Z_2PHONEGROUPS t1 JOIN ZCONTACT t0 ON t0.Z_PK = t1.Z_2INDIVIDUALS WHERE t1.Z_3PHONEGROUPS = ?
//2013-05-19 21:34:42.701 P[9666:c07] CoreData: annotation: sql connection fetch time: 0.0004s
//2013-05-19 21:34:42.701 P[9666:c07] CoreData: annotation: total fetch execution time: 0.0008s for 3 rows.
//2013-05-19 21:34:42.715 P[9666:c07] CoreData: annotation: to-many relationship fault "individuals" for objectID 0x8572b70 <x-coredata://CBE585F2-552D-4FDE-AAEA-2C9C7984FAC9/PhoneGroup/p21> fulfilled from database.  Got 3 rows
//2013-05-19 21:34:42.716 P[9666:c07] CoreData: sql: SELECT t0.Z_ENT, t0.Z_PK, t0.Z_OPT, t0.ZNAME, t0.ZCONTACTID, t0.ZVISIBLE FROM ZCONTACT t0 WHERE  t0.Z_PK = ?
//2013-05-19 21:34:42.717 P[9666:c07] CoreData: annotation: sql connection fetch time: 0.0005s
//2013-05-19 21:34:42.717 P[9666:c07] CoreData: annotation: total fetch execution time: 0.0008s for 1 rows.
//2013-05-19 21:34:42.718 P[9666:c07] CoreData: annotation: fault fulfilled from database for : 0x818cad0 <x-coredata://CBE585F2-552D-4FDE-AAEA-2C9C7984FAC9/Individual/p4>
//2013-05-19 21:34:42.718 P[9666:c07] CoreData: sql: SELECT 0, t0.Z_PK FROM Z_2PHONEGROUPS t1 JOIN ZCONTACT t0 ON t0.Z_PK = t1.Z_3PHONEGROUPS WHERE t1.Z_2INDIVIDUALS = ?
//2013-05-19 21:34:42.719 P[9666:c07] CoreData: annotation: sql connection fetch time: 0.0004s
//2013-05-19 21:34:42.719 P[9666:c07] CoreData: annotation: total fetch execution time: 0.0008s for 1 rows.
//2013-05-19 21:34:42.719 P[9666:c07] CoreData: annotation: to-many relationship fault "phoneGroups" for objectID 0x818cad0 <x-coredata://CBE585F2-552D-4FDE-AAEA-2C9C7984FAC9/Individual/p4> fulfilled from database.  Got 1 rows
//2013-05-19 21:34:42.720 P[9666:c07] CoreData: sql: SELECT 0, t0.Z_PK FROM ZREMINDER t0 WHERE  t0.ZCONTACT = ?
//2013-05-19 21:34:42.721 P[9666:c07] CoreData: annotation: sql connection fetch time: 0.0005s
//2013-05-19 21:34:42.721 P[9666:c07] CoreData: annotation: total fetch execution time: 0.0008s for 0 rows.
//2013-05-19 21:34:42.721 P[9666:c07] CoreData: annotation: to-many relationship fault "reminders" for objectID 0x818cad0 <x-coredata://CBE585F2-552D-4FDE-AAEA-2C9C7984FAC9/Individual/p4> fulfilled from database.  Got 0 rows
//2013-05-19 21:34:42.722 P[9666:c07] CoreData: sql: SELECT t0.Z_ENT, t0.Z_PK, t0.Z_OPT, t0.ZNAME, t0.ZCONTACTID, t0.ZVISIBLE FROM ZCONTACT t0 WHERE  t0.Z_PK = ?
//2013-05-19 21:34:42.722 P[9666:c07] CoreData: annotation: sql connection fetch time: 0.0004s
//2013-05-19 21:34:42.722 P[9666:c07] CoreData: annotation: total fetch execution time: 0.0008s for 1 rows.
//2013-05-19 21:34:42.723 P[9666:c07] CoreData: annotation: fault fulfilled from database for : 0x818cb90 <x-coredata://CBE585F2-552D-4FDE-AAEA-2C9C7984FAC9/Individual/p16>
//2013-05-19 21:34:42.723 P[9666:c07] CoreData: sql: SELECT 0, t0.Z_PK FROM Z_2PHONEGROUPS t1 JOIN ZCONTACT t0 ON t0.Z_PK = t1.Z_3PHONEGROUPS WHERE t1.Z_2INDIVIDUALS = ?
//2013-05-19 21:34:42.724 P[9666:c07] CoreData: annotation: sql connection fetch time: 0.0004s
//2013-05-19 21:34:42.724 P[9666:c07] CoreData: annotation: total fetch execution time: 0.0008s for 1 rows.
//2013-05-19 21:34:42.724 P[9666:c07] CoreData: annotation: to-many relationship fault "phoneGroups" for objectID 0x818cb90 <x-coredata://CBE585F2-552D-4FDE-AAEA-2C9C7984FAC9/Individual/p16> fulfilled from database.  Got 1 rows
//2013-05-19 21:34:42.725 P[9666:c07] CoreData: sql: SELECT 0, t0.Z_PK FROM ZREMINDER t0 WHERE  t0.ZCONTACT = ?
//2013-05-19 21:34:42.725 P[9666:c07] CoreData: annotation: sql connection fetch time: 0.0004s
//2013-05-19 21:34:42.726 P[9666:c07] CoreData: annotation: total fetch execution time: 0.0008s for 0 rows.
//2013-05-19 21:34:42.726 P[9666:c07] CoreData: annotation: to-many relationship fault "reminders" for objectID 0x818cb90 <x-coredata://CBE585F2-552D-4FDE-AAEA-2C9C7984FAC9/Individual/p16> fulfilled from database.  Got 0 rows
//2013-05-19 21:34:42.727 P[9666:c07] CoreData: sql: SELECT t0.Z_ENT, t0.Z_PK, t0.Z_OPT, t0.ZNAME, t0.ZCONTACTID, t0.ZVISIBLE FROM ZCONTACT t0 WHERE  t0.Z_PK = ?
//2013-05-19 21:34:42.727 P[9666:c07] CoreData: annotation: sql connection fetch time: 0.0004s
//2013-05-19 21:34:42.727 P[9666:c07] CoreData: annotation: total fetch execution time: 0.0008s for 1 rows.
//2013-05-19 21:34:42.728 P[9666:c07] CoreData: annotation: fault fulfilled from database for : 0x818cba0 <x-coredata://CBE585F2-552D-4FDE-AAEA-2C9C7984FAC9/Individual/p17>
//2013-05-19 21:34:42.728 P[9666:c07] CoreData: sql: SELECT 0, t0.Z_PK FROM Z_2PHONEGROUPS t1 JOIN ZCONTACT t0 ON t0.Z_PK = t1.Z_3PHONEGROUPS WHERE t1.Z_2INDIVIDUALS = ?
//2013-05-19 21:34:42.729 P[9666:c07] CoreData: annotation: sql connection fetch time: 0.0004s
//2013-05-19 21:34:42.729 P[9666:c07] CoreData: annotation: total fetch execution time: 0.0008s for 4 rows.
//2013-05-19 21:34:42.729 P[9666:c07] CoreData: annotation: to-many relationship fault "phoneGroups" for objectID 0x818cba0 <x-coredata://CBE585F2-552D-4FDE-AAEA-2C9C7984FAC9/Individual/p17> fulfilled from database.  Got 4 rows
//2013-05-19 21:34:42.730 P[9666:c07] CoreData: sql: SELECT 0, t0.Z_PK FROM ZREMINDER t0 WHERE  t0.ZCONTACT = ?
//2013-05-19 21:34:42.730 P[9666:c07] CoreData: annotation: sql connection fetch time: 0.0004s
//2013-05-19 21:34:42.731 P[9666:c07] CoreData: annotation: total fetch execution time: 0.0007s for 0 rows.
//2013-05-19 21:34:42.731 P[9666:c07] CoreData: annotation: to-many relationship fault "reminders" for objectID 0x818cba0 <x-coredata://CBE585F2-552D-4FDE-AAEA-2C9C7984FAC9/Individual/p17> fulfilled from database.  Got 0 rows

拟议的实施表现:

//2013-05-19 21:13:26.734 P[9609:c07] CoreData: sql: SELECT t0.Z_ENT, t0.Z_PK, t0.Z_OPT, t0.ZNAME, t0.ZCONTACTID, t0.ZVISIBLE FROM ZCONTACT t0 JOIN Z_2PHONEGROUPS t1 ON t0.Z_PK = t1.Z_2INDIVIDUALS WHERE ((t1.Z_3PHONEGROUPS = ? AND (SELECT COUNT(t3.Z_3PHONEGROUPS) FROM Z_2PHONEGROUPS t3 WHERE (t0.Z_PK = t3.Z_2INDIVIDUALS) ) = ? AND (SELECT COUNT(t4.Z_PK) FROM ZREMINDER t4 WHERE (t0.Z_PK = t4.ZCONTACT) ) = ?) AND  t0.Z_ENT = ?)
//2013-05-19 21:13:26.735 P[9609:c07] CoreData: annotation: sql connection fetch time: 0.0008s
//2013-05-19 21:13:26.736 P[9609:c07] CoreData: annotation: total fetch execution time: 0.0012s for 2 rows.

数据构建(- (void) synthesizePhoneGroupsAndIndividuals:(NSManagedObjectContext*)context):

NSMutableArray* individuals = [NSMutableArray new];//[NSEntityDescription insertNewObjectForEntityForName:@"Individual" inManagedObjectContext:context];
for (NSUInteger i = 0; i < (3 + arc4random() % 100); ++i) {
    Individual* indi = [NSEntityDescription insertNewObjectForEntityForName:@"Individual" inManagedObjectContext:context];
    indi.contactID = [NSString stringWithFormat:@"cid-%u",i];
    [individuals addObject:indi];
}

NSMutableArray* groups = [NSMutableArray new];
for (NSUInteger i = 0; i < 3 + arc4random() % 7; ++i) {
    PhoneGroup* group = [NSEntityDescription insertNewObjectForEntityForName:@"PhoneGroup" inManagedObjectContext:context];
    group.visible = NO;
    NSMutableSet* indis = [group mutableSetValueForKey:@"individuals"];
    for (NSUInteger j = 0; j < 3; ++j) {
        [indis addObject:[individuals objectAtIndex:(arc4random() % [individuals count])]];
    }
    [groups addObject:group];
}

[context save:NULL];

测试代码:

NSManagedObjectContext* context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
context.persistentStoreCoordinator = _persistentStoreCoordinator;

[context performBlockAndWait:^{
    [self synthesizePhoneGroupsAndIndividuals:context];
    [context reset];
}];

[context performBlockAndWait:^{
    NSFetchRequest* r = [[NSFetchRequest alloc] initWithEntityName:@"PhoneGroup"];
    NSArray* groups = [context executeFetchRequest:r error:NULL];
    if ([groups count]) {
        PhoneGroup* group = [groups objectAtIndex:(arc4random() % [groups count])];
        [context deleteObject:group];
    }
}];

答案 1 :(得分:0)

我怀疑你的问题可能是因为提前调用[super prepareForDeletion];造成的。你应该做你想做的工作然后打电话[super prepareForDeletion];

答案 2 :(得分:0)

游戏后期,但我只是遇到了一些类似的问题。

您的商店是否在iCloud上?

我的问题与我在iCloud上使用coredata的事实有关。 即使在调用mergeChangesFromContextDidSaveNotification之前,来自iCloud的已删除对象可能已经无法再访问其属性和相关实体。

我最终没有直接使用任何已删除的对象,也没有依赖prepareForDeletion来访问我需要的数据。

相反,我缓存此信息(在用户设置中适用于我的用例),使用objectID键入。删除后,我使用通知用户信息的NSDeletedObjectsKey中找到的objectID检索该信息。之后删除缓存的信息。