2012-05-03 68 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帮助:( –