iOS - Фоновые процессы и обновление пользовательского интерфейса - PullRequest
3 голосов
/ 04 августа 2011

вопрос прост: мое приложение контролирует наличие обновлений при каждом запуске.Если есть обновление, всплывающее окно будет отображаться с выбором Да или Нет.Когда пользователь нажимает Да, запускаются 4 метода.Эти методы загружают XML-файл и загружают CoreData.Это код предупреждения:

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {

    if (buttonIndex==1) {
        [self showActivityViewer];
        [self downloadControlAndUpdatePoi];
        [self downloadControlAndUpdateItinerari];
        [self downloadControlAndUpdateArtisti];
        [self downloadControlAndUpdateEventi];
        [self hideActivityViewer];
        NSLog(@"AGGIORNA");
    } else {
        NSLog(@"NON AGGIORNARE");
        return;
    }
}

Но есть проблема: когда пользователь нажимает Да, предупреждение не исчезает и остается на экране, пока не завершены все методы.Поэтому я пробую этот другой код:

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {

    if (buttonIndex==1) {
        [self showActivityViewer];
        [NSThread detachNewThreadSelector:@selector(startDownloads) toTarget:self withObject:nil];
        [self hideActivityViewer];
        NSLog(@"AGGIORNA");
    } else {
        NSLog(@"NON AGGIORNARE");
        return;
    }
}

-(void)startDownloads {
    NSInvocationOperation *opPoi=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadControlAndUpdatePoi) object:nil];
    NSInvocationOperation *opItinerari=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadControlAndUpdateItinerari) object:nil];
    NSInvocationOperation *opArtisti=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadControlAndUpdateArtisti) object:nil];
    NSInvocationOperation *opEventi=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadControlAndUpdateEventi) object:nil];
    NSArray *operations=[[NSArray alloc] initWithObjects:opPoi,opItinerari,opArtisti,opEventi, nil];
    NSOperationQueue *queue=[[NSOperationQueue alloc] init];
    [queue addOperations:operations waitUntilFinished:YES];
    [queue waitUntilAllOperationsAreFinished];

}

Даже здесь есть проблема: я нажимаю «Пуск», но средство просмотра активности не появляется.Предупреждение исчезает, и поток запускается и запускает 4 метода один за другим.

Мне нужно, чтобы процессы запускались в фоновом режиме, как это случилось с моим вторым кодом, но мне нужно, чтобы даже мой метод showActityViewer был запущен и показал счетчик.

Спасибо :))

1 Ответ

5 голосов
/ 04 августа 2011

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

-(void)startDownloads {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
    [self downloadControlAndUpdatePoi];
    [self downloadControlAndUpdateItinerari];
    [self downloadControlAndUpdateArtisti];
    [self downloadControlAndUpdateEventi];
    [pool release];
}

Прежде всего, вам нужно определить пул авто-релиза в startDownloads, если вы используете autorelease в методах downloadControl*, в противном случае я подозреваю, что у вас будут утечки.

Относительно того, почему индикатор активности не отображается, это зависит от того, что вы звоните:

    [self hideActivityViewer];

сразу после отсоединения.Итак, вы показываете его и удаляете, до того, как пользовательский интерфейс получит время для обновления.Удалите эту строку оттуда и перепишите startDownloads следующим образом:

-(void)startDownloads {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
    [self downloadControlAndUpdatePoi];
    [self downloadControlAndUpdateItinerari];
    [self downloadControlAndUpdateArtisti];
    [self downloadControlAndUpdateEventi];
    [self performSelectorOnMainThread:@selector(hideActivityViewer) withObject:nil waitUntilDone:NO];  

    [pool release];
}

Здесь обратите внимание, что я звоню в основной поток на hideActivityViewer, поскольку только основной поток может безопасно использовать UIKit.РЕДАКТИРОВАТЬ:

Я не знал, что вы использовали Core Data в методах загрузки ...

Посмотрите на Параллельность с Core Data .Вам нужно будет немного подправить свой код, по крайней мере, используя отдельный контекст управляемого объекта для вашего вторичного потока (я не знаю, возможно ли для вас создать moc там).

Также естьпосмотрите на этот урок из Какао - моя подруга .

В качестве альтернативы всему этому вы могли бы подумать:

if (buttonIndex==1) {
    [self showActivityViewer];
    [self performSelector:@selector(startDownloads) withObject:nil afterDelay:0];
    NSLog(@"AGGIORNA");
} else {
    NSLog(@"NON AGGIORNARE");
    return;
}

с:

-(void)startDownloads {
    [self downloadControlAndUpdatePoi];
    [self downloadControlAndUpdateItinerari];
    [self downloadControlAndUpdateArtisti];
    [self downloadControlAndUpdateEventi];
    [self hideActivityViewer];  
}

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

[self performSelector:@selector(startDownloads) withObject:nil afterDelay:0.1];
...