1

これは本当に奇妙な問題です。私はCore Dataを理解していると思いました。バックグラウンドの変更NSFetchedResultsControllerを使用してNSManagedObjectContextがMainで表示されない

親を持たない背景コンテキストを使用します。永続的な店舗コーディネーターに引き寄せられます。このバックグラウンドコンテキストでオブジェクトを更新して保存します。私はContextDidSaveNotificationを聞いて、それらの変更を私のメインスレッドのコンテキストにマージします。これらの更新されたオブジェクトは、すでに表ビュー・セルを取り込むために使用されているため、メイン・スレッド上の障害ではありません。だから私はそれらの変更が実際にマージすると期待します。しかし、彼らはそうではありません。

私のデータモデルの詳細に慣れていなければ、オブジェクトは "downloadState"というプロパティを持っていれば十分です。バックグラウンドスレッドで解析作業が完了すると、downloadStateValue(enum)は "completed"に対応する "3"に設定されます。

私はContentWillSaveの通知を購読して、何が起こっているのかを確認します。私は私の構文解析作業の最後にこれを取得:QLUserPinnedCourseオブジェクトにlistentingさ

2016-06-13 10:19:21.055 MyApp[29162:52855206] Going to save background context. 
updated:{(
<QLUserPinnedCourse: 0x7fe195403c10> (entity: QLUserPinnedCourse; id: 0xd0000000002c0002 <x-coredata://95821ADC-8A1F-4DAC-B20C-EDD8F8F413EA/QLUserPinnedCourse/p11> ; data: { 
    course = "0xd000000000dc0008 <x-coredata://95821ADC-8A1F-4DAC-B20C-EDD8F8F413EA/QLCourse/p55>"; 
    courseId = 2794; 
    /* other fields redacted */ 
}), 
<QLCourse: 0x7fe1954cded0> (entity: QLCourse; id: 0xd000000000dc0008 <x-coredata://95821ADC-8A1F-4DAC-B20C-EDD8F8F413EA/QLCourse/p55> ; data: { 
/* other fields redacted*/ 
contentDownloadState = 3; 
courseId = 2794; 
pinnedUserData = "0xd0000000002c0002 <x-coredata://95821ADC-8A1F-4DAC-B20C-EDD8F8F413EA/QLUserPinnedCourse/p11>"; 
    }) 

NSFetchedResultsControllerは私のテーブルでセルのリロードをトリガーdelegate呼び出しを、取得します。

述語は次のとおりです。私は、セルのコードを取得するとき

// Specify criteria for filtering which objects to fetch 
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"pinned == %@ && course.contentDownloadState IN %@", 
            @YES, 
            @[@(QLDownloadStateSucceeded), @(QLDownloadStateNotYetAttempted), @(QLDownloadStateFailed), @(QLDownloadStateIncomplete)] 
            ]; 

は今、私はで動作するようにQLUserPinnedCourseオブジェクトを持っています。私は、デバッガでブレークポイントを設定および取得:

(lldb) po userCourse.course 
<QLCourse: 0x7fe19568f740> (entity: QLCourse; id: 0xd000000000dc0008 <x-coredata://95821ADC-8A1F-4DAC-B20C-EDD8F8F413EA/QLCourse/p55> ; data: { 

    contentDownloadState = 1; 
    courseId = 2794; 
    pinnedUserData = "0xd0000000002c0002 <x-coredata://95821ADC-8A1F-4DAC-B20C-EDD8F8F413EA/QLUserPinnedCourse/p11>"; 
}) 

質問はなぜcontentDownloadStateない3であるが、それでも1、あります?理解できません。

これらの変更をマージしてはいけませんか?私のスタックのよう

詳細:

PSC -> Private Concurrent (saving context) -> Main Thread context 

PSC -> Private Concurrent (import context) 

ContextDidSave:私はuserCourseを求めている

_contextSaveObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification 
                      object:nil 
                       queue:nil 
                     usingBlock:^(NSNotification* note) 
          { 
           NSManagedObjectContext *contextSaved = note.object; 
           NSManagedObjectContext *moc = weakself.mainQueueContext; 

           // basically, if this was a background worker thread 

           DDLogDebug(@"updatedObjects:%@", note.userInfo[NSUpdatedObjectsKey]); 

           if ([contextSaved.userInfo[CoreDataUserInfoKeyIsWorkerContext] boolValue]) 
           { 
            [weakself.privateSavingContext performBlock:^(){ 

             for (NSManagedObject *object in note.userInfo[NSUpdatedObjectsKey]) { 
              [[weakself.privateSavingContext objectWithID:[object objectID]] willAccessValueForKey:nil]; 
             } 

             [weakself.privateSavingContext mergeChangesFromContextDidSaveNotification:note]; 

             [moc performBlock:^(){ 

              for (NSManagedObject *object in note.userInfo[NSUpdatedObjectsKey]) { 
               [[moc objectWithID:[object objectID]] willAccessValueForKey:nil]; 
              } 

              [moc mergeChangesFromContextDidSaveNotification:note]; 


             }]; 
            }]; 
           } 
          }]; 

注:コンテキストが輸入状況であった場合、上記の両方のコンテキストに変更をマージ 私のFRCはQLUserPinnedCourseオブジェクトに興味がありますが、その属性の.courseオブジェクトです。私は、QLCourseオブジェクトに関連する述語でキーパスを指定するため、これらの変更がリフレッシュされると考えました。

+0

ダウンロード状態を設定するコードを表示できますか? – orkoden

+0

これはメインスレッドのコンテキストでperformBlockAndWait:callの内部で実行され、最後にPSCに保存するように指示します。コード自体は、私のCore Dataコントローラの詳細を知る必要があるので役に立ちません。そのコードはうまく動作することが証明されています。また、コメントにfixedFontマークアップを許可する必要があります! マージポリシーの問題ですか?私は、ワーカーのコンテキストが作成された後、MTでこれらのプロパティを設定すると思います。そのワーカーはその更新プログラムをマージしませんでした。 – horseshoe7

答えて

1

これはコアデータの奇抜です。実際には、保存操作で更新されたメインコンテキストのオブジェクトを再フォールトする必要があります。

はここスウィフトの例です:

mainContext.performBlock { 
    let updatedObjects : Set<NSManagedObject> = notification.userInfo![NSUpdatedObjectsKey] as! Set<NSManagedObject> 

    for obj in updatedObjects { 
     self.mainContext.objectWithID(obj.objectID).willAccessValueForKey(nil) 
    } 

    self.mainContext.mergeChangesFromContextDidSaveNotification(notification) 
} 

主要部分は、オブジェクトが障害としてマークされますwillAccessValueForKey:nilへの呼び出しです。これにより、メインコンテキストのNSFetchedResultsControllerが発生します。

+0

それは私が1対1の関係であるオブジェクトを見ているからですか?それはリフレッシュされませんか? NSFetchedResultsControllerは "それを気にしません"? – horseshoe7

+0

NSFetchedResultsControllerのデリゲートメソッドは起動します。それはちょうどQLCourseタイプの関連オブジェクトのように思えます? – horseshoe7

+1

関連オブジェクトのプロパティ変更に対して 'NSFetchedResultsController'が起動しません。リレーションシップ自体を変更するだけで変更が発生します。私が自分のコードで行うことは、FRCを強制的に起動させるために、自身(現在の値、例えば 'obj.relationship = obj.relationship')との関係を設定することです。 – Avi

1

私は解決策を見つけましたが、なぜそれが機能するのかはわかりません。

「コンテンツのダウンロードを開始する」という方法があり、メインスレッドのコンテキストでcontentDownloadStateプロパティを「不完全/ダウンロード」に更新してから、すべてのコンテンツを取得することになります。

残りのすべての作業は、バックグラウンドスレッドのコンテキストで行われました。終了したら、その値を '成功'で更新しました。その変更をマージしていませんでした。なぜ私は考えていない。

私は一度、ワーカーのコンテキストですべてを行うことにしました。つまり、その値を変更してコンテキストをディスクに保存します。変更は、すべての変更が伝播しています。

最後に私はそれを解決しましたが、本当に問題を理解していません。

関連する問題