1

我正在- prepareForDeletiona内部进行一些处理NSManagedObject。但是,当我尝试访问此类的某些属性时,它们会返回给我nil(即使我知道它们不是nil)。所以我检查我的对象是否有[self isFault]问题并返回YES

- prepareForDeletion那么当我因为需要访问属性而在里面时,如何使对象“没有错”呢?

PhoneGroup.m (NSManagedObject)

- (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");
}

型号信息:

PhoneGroupIndividual与删除规则无效具有一对多的反比关系。

IndividualPhoneGroup与删除规则无效具有一对多的反比关系。

ContactIndividuals 和PhoneGroups的超类

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

在此处输入图像描述

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

PhoneGroup只有在与 a 有关系时才会出现错误Reminder。如果 a在被删除时PhoneGroup与 a 没有关系,则不是错误。Reminder

ReminderContact与删除规则无效有一个可选的逆对多关系。

ContactReminder与删除规则无效有一个可选的逆对多关系。

这有什么意义?

编辑2:关于这个问题的更多发现

我尝试了 Dan Shelly 的替代解决方案来获取Individuals但是即使self.managedObjectContext( )也在里面NSManagedObject,这意味着什么?PhoneGroupnil- prepareForDeletion

4

3 回答 3

1

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

编辑:
在发现您的managedObjectContextis之后,可以nil肯定地说您的对象已被其上下文否认。
这可能是由上下文reset或释放引起的,而您保持对对象的强引用。
然而,这并不能解释这在prepareForDeletion方法内部是如何发生的。
当实时上下文正在删除对象 () 时,将调用此方法[context deleteObject:...]
这意味着您要么prepareForDeletion手动调用 ( [object prepareForDeletion]),要么另一个线程在删除过程中重置/释放您的上下文。

注意:如果您的对象上有一个有效objectID的活动managedObjectContext集,则下面的代码将起作用。

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

PhoneGroup如果您的已删除对象individuals(然后,您将作为该关系中包含的对象(N 个对象)出现故障,您的循环将一一访问它们(N 次前往商店)。仍然在循环中,您可以访问每个对象的关系(2 个关系船,phoneGroups并且reminders==> 2 次前往每个项目的商店)。
总之: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.

附录:

当前实现性能(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];
    }
}];
于 2013-05-19T18:48:21.693 回答
0

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

你的商店在 iCloud 上吗?

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

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

相反,我缓存了这些信息(在用户设置中对我的用例有好处),并以 objectID 为键。NSDeletedObjectsKey删除后,我使用通知用户信息中的 objectID 检索该信息。之后将删除缓存的信息。

于 2014-10-03T03:22:18.770 回答
0

我怀疑你的问题可能是由于[super prepareForDeletion];这么早打电话引起的。您可能应该做您想做的工作,然后调用[super prepareForDeletion];.

于 2013-05-21T16:53:24.103 回答