Обновление интерфейса какао при обработке кода в отдельном потоке с использованием executeSelectorInBackground - PullRequest
0 голосов
/ 17 октября 2011

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

Эта проблема, конечно, лучше всего решается с использованием нескольких потоков (/1066707/mozhno-li-zapustit-potok-nazhav-knopku-v-interfeise-kakao-i-prodolzhat-ispolzovat-interfeis-vo-vremya-raboty-potoka).

Я реализовал метод executeSelectorInBackground, который (согласно документации) запускает указанный селектор в отдельном потоке. Тем временем мой графический интерфейс обновляется из основного потока путем запроса объекта 'reverter'.

Однако, похоже, что графический интерфейс не обновляется, пока не завершится выполнение кода во вторичном потоке. Очевидно, мне нужно, чтобы они работали параллельно. Вот то, что я получил до сих пор - я был бы очень благодарен за любую помощь, так как это мой первый раз с потоками.

-(IBAction)pushButton:(id)sender{
 //instatiate reverter object, which does all the firmware processing
 Reverter *reverter = [[Reverter alloc] init];  

//update the GUI to show a tab with a progress indicator    
[tabView selectTabViewItemWithIdentifier:@"RevertProgressTab"];

//process revert code in a separate thread  
[reverter performSelectorInBackground:@selector(revertFirmware) withObject:nil];

//process is complete when reverter progress reaches 100
while (!([reverter progress] == 100)) {

    //check for failure
    if ([reverter hasFailed]) {
        [self showRevertFailureTab:nil];
        return;
    }
    //update the progress indicator in the interface
    [revertProgressBar setDoubleValue:(double)[reverter progress]];
    [NSThread sleepForTimeInterval:0.05];
}

[self showRevertSuccessTab:nil];    


}

Сделал ли я что-нибудь очевидное, что помешало бы обновлению графического интерфейса при выполнении метода revertFirmware?

1 Ответ

1 голос
/ 17 октября 2011

Ваш цикл while

while (/*condition*/) {
    [NSThread sleepForTimeInterval:x];
}

не позволит обновить ваш пользовательский интерфейс.Ваш пользовательский интерфейс будет обновляться только после возврата метода pushButton: .

Вместо опроса я бы посоветовал вам начать использовать асинхронную модель событий:

Добавитьделегат вашего объекта ревертера

@protocol ReverterDelegate <NSObject>
- (void) reverterProgressDidUpdate:(float)progress;
@end

@interface Reverter : NSObject {
    id<ReverterDelegate> delegate;
}
@property(assign) id<ReverterDelegate> delegate;
@end

Зарегистрируйте класс контроллера в качестве делегата вашего ревертера

reverter.delegate = self;

и обработайте это событие

- (void) reverterProgressDidUpdate:(float)progress {
    // update ui
}

В фоновом потоке отправляйте события в основной поток

- (void) revertFirmware {
    // once in a while send notifications of progress updates
    if ([self.delegate respondsToSelector:@selector(reverterProgressDidUpdate:)]) {
        [self.delegate performSelectorOnMainThread:@selector(reverterProgressDidUpdate:) withObject:[NSNumber numerWithFloat:progress] waitUntilDone:NO];
    }
}

Убедитесь, что вы сохранили свой ревертер где-нибудь и отпустите его, когда он заработает.Теперь вы используете метод push-кнопки : .Также это всего лишь предложение к лучшей модели.Вместо использования executeSelectorInBackground вы могли бы взглянуть на NSOperation и NSOperationQueue, например.

...