但是UIButton仍然按下,直到xml数据被返回,因此如果这是一个互联网服务的问题,它不能被纠正,应用程序实际上是不可用的.
这里是电话:
{ AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; if(!appDelegate.XMLdataArray.count > 0){ [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; [appDelegate GetApps]; //function that retrieves data from Website and puts into the array - XMLdataArray. } XMLViewController *controller = [[XMLViewController alloc] initWithNibName:@"MedGearsApps" bundle:nil]; [self.navigationController pushViewController:controller animated:YES]; [controller release]; }
它工作正常,但如何使视图按钮功能与卡住.换句话说,我只是想让UIButton和其他UIButton在后台运行起来.
我听说过PerformSelectorInMainThread,但我不能把它正确地练习
任何帮助是赞赏:)
解决方法
您编写的代码在主应用程序线程中运行.但是,当你想到它时,你不必写主要的功能 – 你只需要实现应用程序委托和事件回调(如触摸处理程序),并且以某种方式在时间到来时自动运行.这不是一个魔术,这只是一个名为Run Loop的Cocoa对象.
运行循环是接收所有事件的对象,处理定时器(如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
现在,您的代码执行您想要执行的操作,“运行循环”继续运行.但是,当您的代码完成时间太长,例如在您的情况下,运行循环必须等待,因此在代码完成之前,事件将不会被处理.这是你在应用程序中看到的.
要解决这种情况,你必须在另一个线程中运行长操作.这不是很难,但是你必须考虑几个潜在的问题.在另一个线程中运行可以像调用performSelectorInBackground
一样简单:
[appDelegate performSelectorInBackground:@selector(GetApps) withObject:nil];
而现在你必须考虑一种告诉应用程序已经加载数据的方法,例如在主线程上使用通知或调用选择器.顺便说一下:将数据存储在应用程序委托中(甚至使用应用程序委托来加载数据)不是很优雅的解决方案,但这是另一个故事.
如果您选择performSelectorInBackground解决方案,请查看有关memory management in secondary threads的相关问题.您将需要自己的自动释放池,以便您不会泄露自动释放的对象.
在一段时间后更新答案 – 现在通常最好使用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]; }); });