异步调用Objective C iphone

Sam*_*Sam 9 iphone multithreading asynchronous objective-c

我正在尝试从网站获取数据 - xml.一切正常.

但是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];
}
Run Code Online (Sandbox Code Playgroud)

它工作正常,但如何使视图按钮功能卡住.换句话说,我只是希望UIButton和其他UIButton能够在后台运行时起作用.

我听说performSelectorInMainThread但我不能正确地练习它

任何帮助表示赞赏:)

zou*_*oul 37

你不太了解线程模型,如果你开始添加异步代码而没有真正了解正在发生的事情,你可能会开始自己开枪.

您编写的代码在主应用程序线程中运行.但是当你考虑它时,你不必编写任何main函数 - 你只需要实现应用程序委托和事件回调(例如触摸处理程序),并且它们会在某些时候自动运行.这不是一个魔术,这只是一个名为Run Loop的Cocoa对象.

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
Run Code Online (Sandbox Code Playgroud)

现在yourCode做你想做的事,Run Loop继续运行.但是当你的代码需要很长时间才能完成时(例如在你的情况下),Run Loop必须等待,因此在你的代码完成之前不会处理事件.这是您在应用程序中看到的内容.

要解决这种情况,您必须在另一个线程中运行长操作.这不是很难,但你必须考虑一些潜在的问题.在另一个线程中运行可以像调用一样简单performSelectorInBackground:

[appDelegate performSelectorInBackground:@selector(GetApps) withObject:nil];
Run Code Online (Sandbox Code Playgroud)

现在你必须想办法告诉应用程序数据已被加载,例如使用通知或在主线程上调用选择器.顺便说一句:将数据存储在应用程序委托中(甚至使用应用程序委托来加载数据)并不是非常优雅的解决方案,但这是另一个故事.

如果您确实选择了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];
    });
});
Run Code Online (Sandbox Code Playgroud)