2011-01-12 5 views
0

私は、別のGCDキュー内のワークブロックを実行し、メインスレッドで完了ブロックを実行するNSManagedObjectContextにメソッド-dct_asynchronousTaskWithWorkBlock:completionBlock:を追加しました。この方法は、以下のん:2つのブロックにわたる変数の使用

  1. は、他のキュー
  2. に使用する2番目の管理対象オブジェクトコンテキストは、この新しいコンテキスト
  3. とワークブロックを呼び出し作成呼び出し
  4. を保存し、自分自身にそのコンテキストをマージ自己完結ブロック

この追加はGitHubに見ることができます。

私の問題は、完了ブロックで参照したいワークブロック内に新しいUser管理対象オブジェクトを作成することです。私は解決策はそうのようなオブジェクトIDへの参照を作成するだろうと思った:

__block NSManagedObjectID *objectID = nil; 

[self.managedObjectContext dct_asynchronousTaskWithWorkBlock:^(NSManagedObjectContext *moc) { 

    NSManagedObject *user = // create new user. 

    objectID = [user objectID]; 

} completionBlock:^(NSManagedObjectContext *moc) { 

    NSManagedObject *user = [moc objectWithID:objectID]; 

}]; 

Iはまた、ブロックをコピーしようとしていると、両方のケースで、私は完了ブロックにおけるオブジェクトIDにEXC_BAD_ACCESSを取得します。

ワークブロック内のユーザのobjectIDを補完ブロックから参照することはできますか?または、カテゴリメソッドで参照を渡すのを処理する方法で作業する必要がありますか。

更新:

ルカ最初に、ユーザは、バックグラウンドスレッドであり、第二に、ユーザが主にあるように、ブロック呼び出しにわたって保持について正しかったです。私は今、これは奇妙に見えるかどうかを疑問に思って

__block NSManagedObjectID *objectID = nil; 

[self.managedObjectContext dct_asynchronousTaskWithWorkBlock:^(NSManagedObjectContext *moc) { 

    NSManagedObject *user = // create new user. 

    objectID = [user objectID]; 
    [objectID retain]; 

} completionBlock:^(NSManagedObjectContext *moc) { 

    NSManagedObject *user = [moc objectWithID:objectID]; 
    [objectID release]; 

}]; 

これが現時点での私の修正があります。このコードを読んでいるときに、漏れがあるかどうかを尋ねるかもしれません。最初のブロックで何が起こったのかにかかわらず、カテゴリが完全にブロックを呼び出すのは間違いないが、このコードからちょうど分かりやすいかどうかはわかりません。

+1

ワークブロックにobjectIDを保持し、完了ブロックで再び解放するとどうなりますか?ブロック呼び出しの間にobjectIDが解放される可能性があります(元のユーザーオブジェクトが解放されたため)。 –

+0

元気で元のオブジェクトIDを保持し、完了時に解放しました。このコードから、両方のブロックが呼び出されることは明らかではありません。たとえそれがわかっていても、どのように感じるのかはわかりません。 :) –

答えて

1

あなたのカテゴリの目的は二MOCのセットアップとティアダウンに関連する任意のコードの明確なあなたの仕事と完成ブロックを維持する場合は、作業ブロックから終了ブロックを返すことができます:

[self.managedObjectContext dct_asynchronousTask:^(NSManagedObjectContext *moc) { 

    NSManagedObject *backgroundThreadUser = // create new user. 
    NSManagedObjectID *objectID = [backgroundThreadUser objectID]; 

    return ^(NSManagedObjectContext *moc) { 
     NSManagedObject *mainThreadUser = [moc objectWithID:objectID]; 
     // ... 
    }; 
}]; 
+0

うん、これはかなりうまくいくと思います。昨夜、私は、ワークブロックが完了ブロックに渡すオブジェクトを返すルートを辿ることを考えていましたが、それは私にとってはちょっとうんざりです。これは完璧と思われます。 –

2

ルークは

なぜですべての作業ブロックと終了ブロックがありますか?右ですが、...

GCDのAPIは、元々のように見えた:

dispatch_async(q, workBlock, completionBlock); 

しかし、それは愚かであることが判明しました。 WorkBlockはいつ完了したかを知っています。なぜ、完了ロジックをworkBlockに入れるのはなぜですか?さらに簡単なAPIを作成する以外にも、ワークブロックから完了ブロックに状態を転送するための派生的なメカニズムを必要としません。


dispatch_async(q, ^{ 
    ... do heavy duty work on background here ... 
    dispatch_async(mainQueue, ^{ 
     ... merge into main queue context here ... 
     ... update UI ... 
    }); 
}); 
+0

はい、それは理にかなっています。単にdispatch_async(dispatch_get_main_queue()、^ {/ *補完ブロック* /})を使用してください。作業ブロックの終わりに。 – hatfinch

+0

ここで問題となるのは、管理対象オブジェクトのコンテキストをカテゴリメソッドによって処理されるメインコンテキストにマージする必要があるということです。このメソッドの背後にある理由はどこにでもコンテキストマージコードを書き込まないためです。 –

+0

残念ながら、ヒットリターンし、あまりにも長い編集を費やしました...ここで問題となるのは、バックグラウンドキューのコンテキストで作成されたオブジェクトを使用するには、マネージオブジェクトコンテキストをメインコンテキストにマージする必要があるということです。これは、workBlockとcompletionBlockを呼び出す間のカテゴリメソッドによって処理されます。この方法の背後にある主な理由は、コンテキストマージコードをどこにでも書いているわけではないからです。このアプローチは、既存の管理対象オブジェクトを更新する必要があるとき、または新しいオブジェクトに関連するオブジェクトへの参照があるときに、他のすべての時点でうまくいきました。 –

関連する問題