我在- 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
的反比关系与删除规则无效。
Individual
与Individual
的反比关系与删除规则无效。
PhoneGroup
是Contact
和Individual
s的超类
这是一个可以更好地可视化的图像。
PhoneGroup
存在关系时, PhoneGroup
似乎只会出错。如果Reminder
在被删除时与PhoneGroup
没有关系,则不错误。
Reminder
与Reminder
具有可选的反对多关系,并且删除规则为null。
Contact
与Contact
具有可选的反对多关系,并且删除规则为null。
这给了什么?
我试图丹雪莉的替代解决方案做了取的Reminder
Š的然而均匀的Individual
的{{1}}(self.managedObjectContext
)是NSManagedObject
在PhoneGroup
里面,这意味着什么?
答案 0 :(得分:1)
[self.individuals allObjects]
为什么返回nil?
修改强>
在发现您的managedObjectContext
为nil
之后,可以肯定地说您的对象已被其上下文所否定。
这可能是由上下文reset
或取消分配引起的,同时您保持对对象的强引用
但是,这并不能解释prepareForDeletion
方法中如何发生这种情况
当实时上下文删除对象([context deleteObject:...]
)时,将调用此方法
这意味着要么手动调用prepareForDeletion
([object prepareForDeletion]
),要么另一个线程在删除中删除你的上下文。
注意:鉴于您的对象上设置了有效
objectID
和实时managedObjectContext
,以下代码将有效。
然而,我可能有一个解决方法,因为您访问数据的方式效率低下(稍后会解释):
如果您删除的对象(PhoneGroup
)individuals
关系没有出现故障,CoreData将最终访问商店以确定关系(第一次旅行)。然后,您将有错误作为该关系中包含的对象(N个对象),您的循环将逐个访问它们(N次前往商店)。仍然在循环中,您访问每个对象的关系(2个关系发货,phoneGroups
和reminders
==&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检索该信息。之后删除缓存的信息。