2012-05-03 18 views
3

スレッドに問題があります。 スレッドがビジー状態のときに、2つの画面の間で数回セグをした後。スレッドはすべての行を実行しません..、メインスレッドに戻る必要があるときにブレークポイントは消えます。 誰か助けてくれますか?iOS - スレッドはメインスレッドに戻りません

ビューがアンロードされたときにスレッドを解放します。

おかげで、次のコード

- (void)fetchFeedDataIntoDocument 
{ 
    NSString * labelString = [NSString stringWithFormat:@"Feed Fetcher %@", self.pageTitle]; 
    const char *label = [labelString UTF8String]; 

    self.fetchF = dispatch_queue_create(label, NULL); 
    dispatch_async(self.fetchF, ^{ 

     NSArray *feeds = [FeedFetcher getDataForJson:self.pageTitle downloadBy:@"up"]; 

     NSDictionary *lastfeed; 

     AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; 

     NSManagedObjectContext *context = [appDelegate getManagedObjectContext]; 

     if ([feeds count] > 0) 
     { 
      lastfeed = [feeds objectAtIndex:0]; 

      [FeedFetcher setLastUpdateIdToCatgorie:self.pageTitle WithId:[lastfeed objectForKey:@"id"] AndPulishDate:[lastfeed objectForKey:@"publish_up"]]; 
     } 

     for (NSDictionary *feedInfo in feeds) { 
      [Feed FeedWithInfo:feedInfo InManageObject:context]; 
     } 

     NSError *error = nil; 

     [context save:&error]; 

     if (error){ 
      NSLog(@"Error save : %@", error);} 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      [self setupFetchedResultsController]; 
      [self.tableView reloadData]; 
      [self downloadImagesForFeeds:feeds]; 
     }); 

    }); 

答えて

11

。これはCore Data Threading Rule#1です。

あなたはMOCをアプリケーションデリゲートから取得しています。それが通常のXcodeで生成されたMOCの場合、スレッド制限の同時実行性で作成されます。 performBlockを呼び出すことさえできません。メインスレッドからは、そのMOCにしかアクセスできません。期間。せいぜい、他の何もかもが火で遊んでいます。

すべての作業を別のスレッドで実行したい場合は、別のMOCも必要です。このように(ちょうど型付け - コンパイルされていない)...このような何かに変換でしょう

NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
moc.parentContext = appDelegate.managedObjectContext; 
[moc performBlock:^{ 
    // Go get your remote data and whatever you want to do 

    // Calling save on this MOC will push the data up into the "main" MOC 
    // (though it is now in the main MOC it has not been saved to the store). 
    [moc save:&error]; 
}]; 

...

- (void)fetchFeedDataIntoDocument 
{ 
    NSString * labelString = [NSString stringWithFormat:@"Feed Fetcher %@", self.pageTitle]; 
    const char *label = [labelString UTF8String]; 

    AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; 
    NSManagedObjectContext *mainContext = [appDelegate getManagedObjectContext]; 
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
    context.parentContext = mainContext; 
    [context performBlock:^{  
     NSArray *feeds = [FeedFetcher getDataForJson:self.pageTitle downloadBy:@"up"]; 

     NSDictionary *lastfeed; 


     if ([feeds count] > 0) 
     { 
      lastfeed = [feeds objectAtIndex:0]; 

      [FeedFetcher setLastUpdateIdToCatgorie:self.pageTitle WithId:[lastfeed objectForKey:@"id"] AndPulishDate:[lastfeed objectForKey:@"publish_up"]]; 
     } 

     for (NSDictionary *feedInfo in feeds) { 
      [Feed FeedWithInfo:feedInfo InManageObject:context]; 
     } 

     NSError *error = nil; 

     [context save:&error]; 

     if (error){ 
      NSLog(@"Error save : %@", error);} 
DO you really want to continue on error? 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      // Data has been pushed into main context from the background 
      // but it still needs to be saved to store... 
      // Do not forget to perform error handling... 
      NSError *error = nil; 
      [mainContext save:&error]; 
      [self setupFetchedResultsController]; 
      [self.tableView reloadData]; 
      [self downloadImagesForFeeds:feeds]; 
     }); 

    }); 

EDIT

作成するためのXcodeによって生成されたコードをMOCはNSConfinementConcurrencyTypeを使用するinitを使用します。 MainConcurrencyで問題なく置き換えることができますが、いくつかの利点があります。アプリのデリゲートファイルで

、交換してください...これで

__managedObjectContext = [[NSManagedObjectContext alloc] init]; 

...

__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 

ここで、メインのMOCを「ペアレント化」することができます。また、performBlockを呼び出すこともできます。

+1

私はこのエラーが発生しました:)、キャッチされていない例外' NSInvalidArgumentException 'のためにアプリケーションを終了しています。理由:'親NSManagedObjectContextはNSPrivateQueueConcurrencyTypeまたはNSMainQueueConcurrencyTypeのいずれかを使用する必要があります。 ' –

+2

OK、 "Xcodeテンプレートで作成されたMOC。 –

+0

ありがとう、ありがとう、私はそれが解決したと思う:D、それは今うまく動いている –

0

変更...たぶん

dispatch_queue_t queue1 = dispatch_queue_create("com.MyApp.AppTask",NULL); 
    dispatch_queue_t main = dispatch_get_main_queue(); 
    dispatch_async(queue1, 
       ^{ 
        dispatch_async(main, 
            ^{ 
             [self setupFetchedResultsController]; 
             [self.tableView reloadData]; 
             [self downloadImagesForFeeds:feeds]; 

            }); 

       }); 

希望、これはこのことについて、あなたに

+0

私のサファリはコードブロック、URLオプションを表示していません。だから私はコードブロックを追加しませんでした。私はコードブロックオプションを参照した後に編集します.. – Nit

+0

私は助けなかった:( –

0

何をするのに役立ちます...

-(void)functionToCallFetch { 

    [self performSelectorInBackground:@selector(fetchFeedDataIntoDocument) withObject:nil]; 

} 

- (void)fetchFeedDataIntoDocument 
{ 

    NSArray *feeds = [FeedFetcher getDataForJson:self.pageTitle downloadBy:@"up"]; 

     NSDictionary *lastfeed; 

     AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; 

     NSManagedObjectContext *context = [appDelegate getManagedObjectContext]; 

     if ([feeds count] > 0) 
     { 
      lastfeed = [feeds objectAtIndex:0]; 

      [FeedFetcher setLastUpdateIdToCatgorie:self.pageTitle WithId:[lastfeed objectForKey:@"id"] AndPulishDate:[lastfeed objectForKey:@"publish_up"]]; 
     } 

     for (NSDictionary *feedInfo in feeds) { 
      [Feed FeedWithInfo:feedInfo InManageObject:context]; 
     } 

     NSError *error = nil; 

     [context save:&error]; 

     if (error){ 
      NSLog(@"Error save : %@", error);} 

     //dispatch_async(dispatch_get_main_queue(), ^{ 
     // [self setupFetchedResultsController]; 
     // [self.tableView reloadData]; 
     // [self downloadImagesForFeeds:feeds]; 
     //}); 
     [self performSelectorOnMainThread:@selector(setupFetchedResultsController) withObject:nil waitUntilDone:NO]; 
     [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO]; 
     [self performSelectorOnMainThread:@selector(downloadImagesForFeeds:) withObject:feeds waitUntilDone:NO]; 


} 

それはうまくいくだろうか?

+0

Mmm ...それはまだ同じです:(セレクタを実行するときにブレークポイントが消えるだけです –

0

あなたのような方法を構築しようとしました:

- (void)methodToBePerformedOnMainThread{ 
     [self setupFetchedResultsController]; 
     [self.tableView reloadData]; 
     [self downloadImagesForFeeds:feeds]; 
} 

fetchFeedDataIntoDocument

編集の最後で

[self performSelectorOnMainThread:@selector(methodToBePerformedOnMainThread) withObject:nil waitUntilDone:NO]; 

でそれを呼び出す:

あなたがラップしてみましたdispatch_queueの代わりにNSOperationQueueを使用しますか?

のように:あなたは、それが作成された場所とは異なるスレッドからmanagedObjectContextにアクセスしている

NSOperationQueue *operationQueue = [NSOperationQueue new]; 

NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(fetchFeedDataIntoDocument) object:nil]; 

if(operation != nil){ 
    [operationQueue addOperation:operation]; 
+0

まだ同じです。 '助けられました:( –

関連する問題