您不太了解线程模型,如果您在没有真正了解发生了什么的情况下开始添加异步代码,您可能会搬起石头砸自己的脚。
您编写的代码在主应用程序线程中运行。但当你想一想,你不必写“不”main
函数 - 您只需实现应用程序委托和事件回调(例如触摸处理程序),并且它们会在时间到来时自动运行。这不是魔法,这只是一个名为 a 的 Cocoa 对象Run Loop.
Run Loop 是一个接收所有事件、处理计时器的对象(如NSTimer
)并运行您的代码。这意味着,例如,当您在用户点击按钮时执行某些操作时,调用树看起来有点像这样:
main thread running
main run loop
// fire timers
// receive events — aha, here we have an event, let’s call the handler
view::touchesBegan…
// use tapped some button, let’s fire the callback
someButton::touchUpInside
yourCode
Now yourCode
做你想做的事情并且运行循环继续运行。但是,当您的代码需要很长时间才能完成时(例如您的情况),运行循环必须等待,因此在代码完成之前不会处理事件。这就是您在应用程序中看到的内容。
要解决这种情况,您必须在另一个线程中运行长操作。这并不难,但您仍然必须考虑一些潜在的问题。在另一个线程中运行就像调用一样简单performSelectorInBackground:
[appDelegate performSelectorInBackground:@selector(GetApps) withObject:nil];
现在您必须想办法告诉应用程序数据已加载,例如使用通知或在主线程上调用选择器。顺便说一句:将数据存储在应用程序委托中(或者甚至使用应用程序委托来加载数据)并不是非常优雅的解决方案,但那是另一个故事了。
如果您选择performSelectorInBackground
解决方案,看一下相关问题辅助线程中的内存管理。您需要自己的自动释放池,这样就不会泄漏自动释放的对象。
一段时间后更新答案——现在通常最好使用 Grand Central Dispatch 在后台运行代码:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// No explicit autorelease pool needed here.
// The code runs in background, not strangling
// the main run loop.
[self doSomeLongOperation];
dispatch_sync(dispatch_get_main_queue(), ^{
// This will be called on the main thread, so that
// you can update the UI, for example.
[self longOperationDone];
});
});