Objective C асинхронного вызова iPhone

Я пытаюсь получить данные из веб-сайта - 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];
}

Это хорошо работает, но как я могу сделать кнопки представления функциональными с застреванием. Другими словами, я просто хочу, чтобы UIButton и другой UIButtons были функциональной хитростью вещь работы в фоновом режиме.

Я слышал о performSelectorInMainThread, но я не могу поместить его для осуществления правильно

любая справка ценится :)

9
задан Sam 25 April 2010 в 15:41
поделиться

4 ответа

Вы плохо разбираетесь в потоковой модели и, вероятно, собираетесь выстрелить себе в ногу, если начнете добавлять асинхронный код, не понимая, что происходит на.

Написанный вами код выполняется в основном потоке приложения. Но когда вы думаете об этом, вам не нужно писать никакой функции main - вы просто реализуете делегат приложения и обратные вызовы событий (например, обработчики касаний), и каким-то образом они запускаются автоматически, когда приходит время. Это не волшебство, это просто объект Какао, называемый 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

Теперь 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];
    });
});
37
ответ дан 4 December 2019 в 06:19
поделиться

Используйте метод NSURLConnection connectionWithRequest: delegate: . Это приведет к асинхронной отправке указанного запроса. Делегат должен ответить на соединение: didReceiveResponse: и будет отправлено это сообщение, как только ответ будет полностью получен.

3
ответ дан 4 December 2019 в 06:19
поделиться

Похоже, вы используете NSURLConnection внутри своего метода getApps. Если да, вам следует преобразовать его в асинхронный вызов.

0
ответ дан 4 December 2019 в 06:19
поделиться

Можно использовать фоновую операцию, которая попадает в очередь операций:

BGOperation *op = [[BGOperation alloc] init];
[[self operationQueue] addOperation:op];
[op release];

Я создал определенные "команды", которые выполняются в фоновом режиме:

@implementation BGOperation

# pragma mark Memory Management

- (BGOperation *)init
{
if ((self = [super init]) != nil)
    /* nothing */;
return self;
}

- (void)dealloc
{
self.jobId = nil;
[super dealloc];
}

# pragma mark -
# pragma mark Background Operation

- (void)main
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [appDelegate GetApps];
[pool release];
return;
}

@end

После завершения может быть хорошей идеей послать уведомление в основной поток, потому что внутренняя база данных была изменена.

0
ответ дан 4 December 2019 в 06:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: