1

の内部- prepareForDeletionで処理を行ってい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との関係がある場合にのみ障害があるようReminderです。aが削除されるときにPhoneGroupa との関係がない場合、それは問題ではありませんReminder

ReminderオプションContactで、削除ルール無効化との逆対多関係があります。

ContactオプションReminderで、削除ルール無効化との逆対多関係があります。

これは何を与えるのですか?

EDIT 2:問題に関するその他の調査結果

Individuals のフェッチを行うために Dan Shelly の代替ソリューションを試してみましたself.managedObjectContextNSManagedObject( PhoneGroup)のnil中にさえありますが、- prepareForDeletionこれは何を意味しますか?

4

3 に答える 3

1

なぜ[self.individuals allObjects]nil を返すのですか?

編集:あなたがあなたのものであること
を発見した後、あなたのオブジェクトはそのコンテキストによって勘当されていると言っても過言ではありません. これは、オブジェクトへの強い参照を維持している間に 、コンテキストまたは割り当て解除が原因である可能性があります。 ただし、これはメソッド内でこれがどのように発生するかを説明しません。 このメソッドは、ライブ コンテキストがオブジェクトを削除しているときに呼び出されます ( )。これは、手動で 呼び出すか( )、別のスレッドが削除の途中でコンテキストをリセット/割り当て解除していることを意味します。managedObjectContextnil
reset
prepareForDeletion
[context deleteObject:...]
prepareForDeletion[object prepareForDeletion]

注: 以下のコードは、オブジェクトに有効なobjectIDライブmanagedObjectContextセットがある場合に機能します。

ただし、データへのアクセス方法がやや非効率的であるため、回避策があるかもしれません (すぐに説明します)。

削除されたオブジェクト ( PhoneGroup)individualsの関係に障害がない場合、CoreData はストアにアクセスして関係を障害します (1 回目のトリップ)。次に、その関係に含まれるオブジェクトとして障害が発生し (N 個のオブジェクト)、ループはそれらに 1 つずつアクセスします (ストアへの 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 でコアデータを使用していたという事実に関連していました。iCloud から削除されたオブジェクトは、mergeChangesFromContextDidSaveNotification.

削除されたオブジェクトを直接使用したり、prepareForDeletion必要なデータへのアクセスに依存したりすることはありませんでした。

代わりに、objectID をキーにして、この情報をキャッシュします (ユーザー設定は私のユース ケースに適しています)。NSDeletedObjectsKey削除したら、通知ユーザー情報の objectID を使用してその情報を取得します。その後、キャッシュされた情報は削除されます。

于 2014-10-03T03:22:18.770 に答える