2012-05-03 108 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

你從它被創造,其中在不同的線程訪問managedObjectContext。這是核心數據線程規則#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]; 
     }); 

    }); 

編輯

通過Xcode中創建生成的代碼MOC使用init,它使用NSConfinementConcurrencyType。您可以用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

對不起,現在我的Safari瀏覽器不顯示代碼塊,網址選項。所以我沒有添加代碼塊。我將編輯後,我看到的代碼塊選項... – 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

嗯...這仍然是相同的:(。斷點只是消失時,它的HASE進行選擇 –

0

你嘗試構建一個方法,如:

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

,並在年底與

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

稱之爲fetchFeedDataIntoDocument

編輯:

你嘗試包它用NSOperationQueue代替dispatch_queue?

像:

NSOperationQueue *operationQueue = [NSOperationQueue new]; 

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

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

還是一樣。它沒「T幫助:( –