applicationDidFinishLaunchWithOptions中的dispatch_async调用不按我期望的方式运行

时间:2011-10-20 19:23:15

标签: iphone objective-c multithreading grand-central-dispatch

我完全不熟悉iOS中的线程。我有一个基于标签栏的应用程序,其标签如下:

  • 主屏幕,其按钮仅用于更改selectedSegmentIndex
  • 在init方法[self doLoadData]
  • 中进行大量Web服务调用的信息列表屏幕
  • 另外两个与此无关的屏幕

我希望在实际调用init之前先调用tabBarController.selectedSegmentIndex = 1方法。所以,我在我的applicationDidFinishLaunching

中这样做了

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [Constants configureApp];

self.window.rootViewController = self.navigationController;

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    [[[[tabBarController viewControllers] objectAtIndex:1] topViewController] init ];
    [self.window addSubview:tabBarController.view];
    [self.window makeKeyAndVisible];
});

self.window.rootViewController = self.navigationController; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [[[[tabBarController viewControllers] objectAtIndex:1] topViewController] init ]; [self.window addSubview:tabBarController.view]; [self.window makeKeyAndVisible]; });

这样做的行为就是它确实有用:

  1. 显示Splash Default.png
  2. 显示白屏
  3. 最后使用tabBarController显示MainWindow。
  4. 请帮助,因为我知道我做错了!

2 个答案:

答案 0 :(得分:2)

就像bbum所说,UIKit不是线程安全的。而不是在后台抛出init,问问自己哪个部分使init更慢并且从那里开始工作。

您是从网上加载图片还是解析某些文件?这些是使用Grand Central Dispatch在后台放置的东西的好例子(至少图像的下载部分,显示仍应在主线程中完成)。

不是将整个init包装在一个调度中,而是在视图控制器的init方法中尝试这样的事情:

dispatch_async(queue, ^{
  [self doLoadData]
  dispatch_async(dispatch_get_main_queue(), ^{
    //Set new data to be displayed     
  });
});

确保在执行此操作时,视图在没有数据的情况下看起来没问题(并且在正常下载后加载数据),因为它会在下载完成之前显示。

答案 1 :(得分:1)

你不能随意向队列发送各种任务,并希望它能够正常工作。

除非将类和/或方法明确记录为线程安全,否则它不是线程安全的

同样,您必须非常仔细地设计自己的类以保证线程安全。虽然队列使这更容易做到,但它仍然充满锋利的边缘。

在这种情况下,您正在使用主队列中的UIKit对象。这通常是在一些特定情况之外禁止的。

您需要阅读Concurrency Programming Guide了解详情。