34

私は本当に厄介な問題を抱えていますが、それは解決できないようです。

Core Data に保存されるメッセージを送信すると、ビューがあります。それが完了すると、データベースにランダムなメッセージ (文) を要求し、それをデータベースの他の行にも保存します。

DBからデータをフェッチせずに最後の部分をハードコーディングすると、すべてうまく機能しますが、DBからランダムな行をフェッチするとすぐに狂ってしまいます。

私の AppDelegate.m では:

- (void)save {
    NSAssert(self.context != nil, @"Not initialized");
    NSError *error = nil;
    BOOL failed = [self.context hasChanges] && ![self.context save:&error];
    NSAssert1(!failed,@"Save failed %@",[error userInfo]);
}

- (NSString*)selectRandomSentence
{
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Sentences" inManagedObjectContext:self.managedObjectContext];
    [request setEntity:entity];

    NSError *error = nil;
    NSUInteger count = [self.context countForFetchRequest:request error:&error];

    NSUInteger offset = count - (arc4random() % count);
    [request setFetchOffset:offset];
    [request setFetchLimit:1];

    NSArray *sentenceArray = [self.context executeFetchRequest:request error:&error];

    [request release];

    return [[sentenceArray objectAtIndex:0] sentence];
}

- (NSManagedObjectContext *)context {

    if (_managedObjectContext != nil)
        return _managedObjectContext;

    NSPersistentStoreCoordinator *coordinator = [self coordinator];
    if (coordinator != nil) {
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    }

    return _managedObjectContext;
}

私のChatController.mで:

- (void)didRecieveMessage:(NSString *)message
{
    [self addMessage:message fromMe:NO];
}

#pragma mark -
#pragma mark SendControllerDelegate

- (void)didSendMessage:(NSString*)text {
    [self addMessage:text fromMe:YES];
}

#pragma mark -
#pragma mark Private methods

- (void)responseReceived:(NSString*)response {
    [self addMessage:response fromMe:NO];
}

- (void)addMessage:(NSString*)text fromMe:(BOOL)fromMe {
    NSAssert(self.repository != nil, @"Not initialized");
    Message *msg = [self.repository messageForBuddy:self.buddy];
    msg.text = text;
    msg.fromMe = fromMe;

    if (fromMe)
    {
        [self.bot talkWithBot:text];
    }

    [self.repository asyncSave];

    [self.tableView reloadData];
    [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:[self.buddy.messages count] - 1] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}

My OfflineBot.m で:

- (void)talkWithBot:(NSString *)textFromMe
{
    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    [self didRecieveMessage:[delegate selectRandomSentence]];
}

- (void)didRecieveMessage:(NSString *)message
{
    if ([self.delegate respondsToSelector:@selector(didRecieveMessage:)])
        [self.delegate didRecieveMessage:message];
}

リポジトリ.m

- (Message*)messageForBuddy:(Buddy*)buddy {
    Message *msg = [self.delegate entityForName:@"Message"];
    msg.source = buddy;
    [self.delegate.managedObjectContext refreshObject:buddy mergeChanges:YES];
    return msg;
}

- (void)asyncSave {
    [self.delegate save];
}

エラー:

2012-08-10 00:28:20.526 Chat[13170:c07] * -[AppDelegate 保存] でのアサーションの失敗、/Users/paulp/Desktop/TestTask/Classes/AppDelegate.m:28 2012-08-10 00:28 :20.527 Chat[13170:c07] *キャッチされていない例外 'NSInternalInconsistencyException' が原因でアプリを終了しています。エンティティ: センテンス; id: 0x6b8bf10 ; データ: )" ) 2: {contents = "NSUnderlyingException"} = CoreData は '0x6b8bf10' の障害を実行できませんでした }

私は何を間違っていますか?

更新 エラーをこの行に特定しました:

NSArray *sentenceArray = [self.context executeFetchRequest:request error:&error];

その行を実行すると、エラーが発生します...つまり、データをフェッチするときです。ただし、新しいデータを Messages エンティティに保存すると、エラーが発生するようです。ランダムな文は Sentences から取得されます。

asyncSave メソッドを直接保存するように変更した後 (したがって、新しいスレッドを使用しない)、最初のチャットは保存されますが、その後は保存されません。死ぬ。

更新 my でこれを使用すると、すべてが機能するようですdidFinishLaunchingWithOptions:

[self.context setRetainsRegisteredObjects:YES];

ここでは、CodeData オブジェクト モデル コンテキストがそのオブジェクトを解放しないことを理解しています。これは、追加と保存の間の問題のようです。しかし、なぜ?

4

5 に答える 5

66

うーん。このガイドに従って同時実行を適切に実装していますか? 発生している問題は、複数のスレッドでコア データを使用する場合によくある問題です。オブジェクトは「バックグラウンド コンテキスト」で削除されましたが、別のコンテキストからアクセスされています。[context processPendingChanges]削除後、保存前にバックグラウンド コンテキストを呼び出すと役立つ場合があります。

コア データのパフォーマンスの最適化に関する WWDC 2010 セッション (137) もあります。

fetch Core Data を実行すると、指定した述語に一致するオブジェクトのコレクションが返されます。これらのオブジェクトには、実際にはまだプロパティ値が設定されていません。プロパティにアクセスすると、Core Data はストアに戻って「障害を発生させ」ます。つまり、プロパティにストアからのデータを入力します。Core Data がオブジェクトのプロパティ値を取得するためにストアにアクセスしたが、オブジェクトが永続ストアに存在しない場合、「エラーを実行できませんでした...」という例外が発生します。管理対象オブジェクト コンテキストは、それが存在するはずであると考えました。そのため、障害が発生する可能性があります。これが問題の原因です。例外がスローされる原因となったコンテキストは、このオブジェクトが他の何か (別のコンテキストなど) によってストアから削除されたことを知りませんでした。

上記の同時実行ガイドは現在古くなっていることに注意してください。古いスレッド制限モデルではなく、親子コンテキストとプライベート キューの同時実行を使用する必要があります。親子のコンテキストでは、多くの理由により、「障害を実行できませんでした...」に遭遇する可能性ははるかに低くなります。また、ドキュメンテーション バグを報告するか、フィードバック フォームを使用して同時実行ガイドの更新をリクエストしてください。

于 2012-08-15T23:07:13.670 に答える
6

「コアデータオブジェクト」を異なる行に「保存する」ことは、概念的には実際には不可能です。Core Data はオブジェクト グラフであり、データベースではないことに注意してください。

文を「再配置」したい場合は、文を破棄して再作成するのが最善の方法です。古いインスタンスを保持したい場合は、新しいインスタンスを作成してから、既存のインスタンスからプロパティを入力してください。

破壊するには、使用します

[self.context deleteObject:sentenceObject];

再作成するには、使用します

Sentence *newSentence = [NSEntityDescription insertNewObjectForEntityForName:
  "Sentences" inManagedObjectContext:self.context];
newSentence.sentence = sentenceObject.sentence;
// fill in other properties, then
[self.context save:error];

これについて詳しく知りたい場合は、「Core Data Programming Guide」の「Using Managed Objects」セクションの「 Copying and Copy and Paste 」を参照してください。

于 2012-08-13T13:12:56.167 に答える
1

コアデータメカニズムを確認してください。「障害は、アプリケーションが消費するメモリの量を減らします。障害は、まだ完全には実現されていない管理対象オブジェクトを表すプレースホルダーオブジェクト、または関係を表すコレクションオブジェクトです。」

于 2012-10-30T03:39:55.597 に答える
0

これは、最初の呼び出しのすべての関係のフェッチが完了する前に、新しい行に「ランダムメッセージ」を追加しているために発生します。

最初の呼び出しにプリフェッチを追加して、遅延読み込みを回避できれば、問題は解決すると思います。

これは、リクエストのプリフェッチを実行する方法です。

[request setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects:@"whatEverOfYourWillNumberOne",@"whatEverOfYourWillNumberTwo", nil]];

お役に立てば幸いです。

于 2013-02-25T04:23:35.857 に答える