问题描述
我正在尝试从网站xml获取数据.一切正常.
I'm trying to get data from a website- xml. Everything works fine.
但是UIButton一直保持按下状态,直到返回xml数据为止,因此,如果互联网服务出现问题,将无法更正并且该应用程序实际上无法使用.
But the UIButton remains pressed until the xml data is returned and thus if theres a problem with the internet service, it can't be corrected and the app is virtually unusable.
以下是电话:
{
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在后台运行时起作用.
It works fine, but how can I make the view buttons functional with getting stuck. In other words, I just want the UIButton and other UIButtons to be functional whiles the thing works in the background.
我听说过performSelectorInMainThread
,但是我不能正确地练习.
I heard about performSelectorInMainThread
but I can't put it to practice correctly.
推荐答案
您不太了解线程模型,如果您开始添加异步代码而不真正了解正在发生的事情,那么您可能会一头雾水.
You don’t understand the threading model much and you’re probably going to shoot yourself in the foot if you start adding asynchronous code without really understanding what’s going on.
您编写的代码在主应用程序线程中运行.但是,当您考虑它时,不必编写任何main
函数-您只需实现应用程序委托和事件回调(例如触摸处理程序),并在时间到时以某种方式自动运行它们.这不是魔术,这只是一个称为运行循环.
The code you wrote runs in the main application thread. But when you think about it, you don’t have to write no main
function — you just implement the application delegate and the event callbacks (such as touch handlers) and somehow they run automatically when the time comes. This is not a magic, this is simply a Cocoa object called a Run Loop.
运行循环是一个接收所有事件,处理计时器(如在NSTimer
中)并运行代码的对象.举例来说,这意味着当您在用户点击按钮时执行某项操作时,调用树看起来会像这样:
Run Loop is an object that receives all events, processes timers (as in NSTimer
) and runs your code. Which means that when you, for example, do something when the user taps a button, the call tree looks a bit like this:
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
现在yourCode
完成您想要的操作,并且Run Loop继续运行.但是,当您的代码花费太长时间才能完成时(例如您的情况),运行循环必须等待,因此,直到您的代码完成后,事件才会得到处理.这就是您在应用程序中看到的.
Now yourCode
does what you want to do and the Run Loop continues running. But when your code takes too long to finish, such as in your case, the Run Loop has to wait and therefore the events will not get processed until your code finishes. This is what you see in your application.
要解决这种情况,您必须在另一个线程中运行long操作.这并不是很难,但是您仍然必须考虑一些潜在的问题.在另一个线程中运行就像调用 performSelectorInBackground
:
To solve the situation you have to run the long operation in another thread. This is not very hard, but you’ll have to think of a few potential problems nevertheless. Running in another thread can be as easy as calling performSelectorInBackground
:
[appDelegate performSelectorInBackground:@selector(GetApps) withObject:nil];
现在您必须考虑一种方法来告知应用程序数据已加载,例如使用通知或在主线程上调用选择器.顺便说一句:将数据存储在应用程序委托中(或者甚至使用应用程序委托来加载数据)不是很优雅的解决方案,但这是另一回事了.
And now you have to think of a way to tell the application the data has been loaded, such as using a notification or calling a selector on the main thread. By the way: storing the data in the application delegate (or even using the application delegate for loading the data) is not very elegant solution, but that’s another story.
如果您选择performSelectorInBackground
解决方案,请查看有关辅助线程中的内存管理的相关问题.您将需要自己的自动释放池,以免泄漏自动释放的对象.
If you do choose the performSelectorInBackground
solution, take a look at a related question about memory management in secondary threads. You’ll need your own autorelease pool so that you won’t leak autoreleased objects.
一段时间后更新答案-如今,通常最好使用Grand Central Dispatch在后台运行代码:
Updating the answer after some time – nowadays it’s usually best to run the code in background using 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];
});
});
这篇关于Objective-C中的异步调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!