【问题标题】:App getting stuck in dispatch_async应用程序卡在 dispatch_async 中
【发布时间】:2014-01-08 14:07:34
【问题描述】:

这是我的代码:

        LoadViewController *loadingViewController = [[LoadViewController alloc] initWithNibName:@"LoadViewController" bundle:nil];
[self.view addSubview:loadingViewController.view];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) , ^{
    [Util deleteAllObjects:@"Unit"];
    for (NSDictionary *eachUnit in serviceData) {
        //insert in DB
        AppDelegate* appDelegate = [AppDelegate sharedAppDelegate];
        NSManagedObjectContext *context = appDelegate.managedObjectContext;
        Unit *unit = [NSEntityDescription insertNewObjectForEntityForName:@"Unit" inManagedObjectContext:context];

        unit.id_unidade = [eachUnit objectForKey:@"id"];
        unit.title = [eachUnit objectForKey:@"title"];
        unit.image = [eachUnit objectForKey:@"image"];
        unit.address = [eachUnit objectForKey:@"address"];
        unit.desc = [eachUnit objectForKey:@"desc"];
        unit.coord = [eachUnit objectForKey:@"coord"];

        NSError *error;

        if (![context save:&error]) {
            NSLog(@"Ops,fail: %@", [error localizedDescription]);
        }
    }
    NSLog(@"before");
    [self fillUnits];
    NSLog(@"after");

    dispatch_async(dispatch_get_main_queue(), ^(void) {
        NSLog(@"reload");
        [self.tableView reloadData];
        [loadingViewController.view removeFromSuperview];
        NSLog(@"after reload");

    });
});

它会一直显示到 NSLog(@"after"),但永远不会出现在 NSLog(@"reload") 上。 有什么线索吗??

【问题讨论】:

  • dispatch_async(dispatch_get_main_queue(), ^(void) 中的这个(void)是什么?
  • 我认为我们无法从这个 sn-p 中推断出问题所在。您可能在代码中的其他地方阻塞了主队列。
  • 这是该类的初始化方法的一部分...它在用户点击 UIAlertView 中的取消按钮后被调用...确实 UI 卡住了显示警报...跨度>
  • LoadViewController 在单击取消按钮后被调用,我想......对吗?这看起来不错?
  • 此代码与警报在不同的类中,但是是的...单击取消按钮会调用上面的此方法

标签: ios multithreading activity-indicator


【解决方案1】:

在您的完成处理程序中,您需要确保所有发送到托管对象或托管对象上下文的方法都使用performBlock:performBlockAndWait: 在它们各自的执行上下文上执行:

    NSManagedObjectContext *context = appDelegate.managedObjectContext;
    [context performBlockAndWait:^{
        Unit *unit = [NSEntityDescription insertNewObjectForEntityForName:@"Unit"  inManagedObjectContext:context];

        unit.id_unidade = [eachUnit objectForKey:@"id"];
        unit.title = [eachUnit objectForKey:@"title"];
        unit.image = [eachUnit objectForKey:@"image"];
        unit.address = [eachUnit objectForKey:@"address"];
        unit.desc = [eachUnit objectForKey:@"desc"];
        unit.coord = [eachUnit objectForKey:@"coord"];

        NSError *error;
        if (![context save:&error]) {
            NSLog(@"Ops,fail: %@", [error localizedDescription]);
        }
    }];

如果您的托管对象将在主线程中访问,则 执行上下文 必须等于主线程。

您可以在 Apple Docs 中阅读更多内容:NSManagedObjectContext Reference,尤其是“并发”一章。

【讨论】:

  • 当我尝试使用它时,它会崩溃:由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“只能在使用队列创建的 NSManagedObjectContext 上使用 -performBlockAndWait:。
  • 那么您已经使用“线程限制”(NSConfinementConcurrencyType)创建了一个托管对象上下文。这有点过时了。您应该使用NSPrivateQueueConcurrencyTypeNSMainQueueConcurrencyType。如果您使用“线程限制”,您必须确保在创建托管上下文的同一 线程 上执行发送到上下文或托管对象的任何方法。使用其他并发模型,您可以确保与在指定 queue 上执行的 performBlockperformBlockAndWait 基本相同的要求。
  • 我该怎么做呢?当我们使用 CoreData 创建应用程序时,我只是使用 Xcode 提供的常规上下文。
  • 请点击我的回答中提供的链接。苹果文档展示了如何创建托管对象上下文:- (id)initWithConcurrencyType:(NSManagedObjectContextConcurrencyType)type。另请注意,Xcode 不提供NSManagedContext,它是you。 Core Data 是一个复杂的话题。我建议阅读 Apple 提供的与 Core Data 相关的所有文档。
  • 嗯...当您使用 CoreData 创建应用程序时,它会在 AppDelegate 中创建一些方法,例如 (NSManagedObjectContext*)managedObjectContext,但无论如何感谢,我会更好地查看文档跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-24
  • 1970-01-01
  • 1970-01-01
  • 2013-03-16
  • 2016-01-21
  • 1970-01-01
相关资源
最近更新 更多