2013-12-15 1 views
5

У меня возникли проблемы с обновлением интерфейса пользователя с помощью функции performSelectorOnMainThread. Вот моя ситуация. В моем представленииDidLoad я установил индикатор активности и метку. Затем я вызываю селектор для получения некоторых данных с сервера. Затем я вызываю селектор для обновления пользовательского интерфейса после задержки. Вот код:Objective C- Устранение неполадок UI в главной теме

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    self.reloadSchools = [[UIAlertView alloc] init]; 
    self.reloadSchools.message = @"There was an error loading the schools. Please try again."; 
    self.reloadSchools.title = @"We're Sorry"; 
    self.schoolPickerLabel = [[UILabel alloc]init]; 
    self.schoolPicker = [[UIPickerView alloc] init]; 
    self.schoolPicker.delegate = self; 
    self.schoolPicker.dataSource = self; 
    self.server = [[Server alloc]init]; 
    schoolList = NO; 

    _activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 
    [self.view addSubview:_activityIndicator]; 
    [self.view bringSubviewToFront:_activityIndicator]; 
    [_activityIndicator startAnimating]; 

    [NSThread detachNewThreadSelector: @selector(getSchoolList) toTarget: self withObject: nil]; 
    [self performSelector:@selector(updateUI) withObject:nil afterDelay:20.0]; 
} 

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

-(void)updateUI 
{ 
    self.schools = [_server returnData]; 
    if(!(self.schools == nil)) { 
     [self performSelectorOnMainThread:@selector(fillPickerView) withObject:nil waitUntilDone:YES]; 
    } 
    else { 
     [self performSelectorOnMainThread:@selector(showError) withObject:nil waitUntilDone:YES]; 
    } 
} 

-(void)showError { 
    NSLog(@"show error"); 
    [_activityIndicator stopAnimating]; 
    [self.reloadSchools show]; 
    } 
-(void)fillPickerView { 
    NSLog(@"fill picker view"); 
    schoolList = YES; 
    NSString *schoolString = [[NSString alloc] initWithData:self.schools encoding:NSUTF8StringEncoding]; 
    self.schoolPickerLabel.text = @"Please select your school:"; 
    self.shoolArray = [[schoolString componentsSeparatedByString:@"#"] mutableCopy]; 
    [self.schoolPicker reloadAllComponents]; 
    [_activityIndicator stopAnimating]; 
} 

Когда fillPickerView селектора называется индикатор активности продолжает вращаться, текстовая метка не меняется, и вид выбора не перезагружать его содержание. Может кто-нибудь объяснить мне, почему метод, который я использую, не работает, чтобы обновить мой ui в основном потоке?

+0

вы можете используйте [GCD] (http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html) для отправки ваших данных в другой поток и обновления интерфейса в основном потоке, это лучше, чем использование NSThread. – johnMa

ответ

27
dispatch_async(dispatch_get_global_queue(0, 0), ^{ 
//load your data here. 
dispatch_async(dispatch_get_main_queue(), ^{ 
       //update UI in main thread. 
      }); 
}); 
+0

спасибо за отзыв – angerboy

0

Прежде всего, вы не должны использовать detachNewThreadSelector. Вы должны использовать GCD и отправить фоновые задачи в очередь асинхронных вызовов. Нити очень дороги для создания. GCD делает намного лучшую работу по управлению системными ресурсами.

Игнорируя это, ваш код не имеет для меня большого смысла. Вы отправляете метод getSchoolList для запуска в фоновом потоке. Вы не показываете код, который вы используете в фоновом режиме.

Затем используйте performSelector: withObject: afterDelay для запуска метода updateUI в основном потоке после фиксированной задержки 20 секунд.

updateUI проверяет наличие self.schools, которое предположительно было создано вашим фоновым потоком, и может быть или не быть сделано. Если self.schools IS nil, вы вызываете fillPickerView, используя performSelectorOnMainThread. Это не имеет смысла, потому что если self.schools ничтожно, нет данных для заполнения сборщика.

Если self.schools не ноль, вы видите ошибку, снова используя performSelectorOnMainThread.

Мне кажется, что логика вашей проверки self.schools обратная. Если он равен нулю, вы должны отобразить сообщение об ошибке, и если он НЕ равен нулю, вы должны заполнить сборщик.

Следующая проблема: В обоих случаях вы вызываете performSelectorOnMainThread: withObject: waitUntilDone: из основного потока. Вызов этого метода из основного потока не имеет смысла.

Третья проблема. Не имеет смысла ждать произвольного количества времени для выполнения фоновой задачи до завершения, а затем либо преуспеть, либо сбой. Вы не будете знать, что происходит в течение 20 секунд. Если фоновая задача заканчивается раньше, вы никогда не узнаете.

Вместо этого вы должны указать, что ваша фоновая задача уведомляет основной поток после выполнения задачи. Это было бы правильное использование performSelectorOnMainThread: withObject: waitUntilDone :, при вызове из основного потока это не так. (Опять же, хотя, вы должны реорганизовать этот код, чтобы использовать ГКД, а не с использованием потоков непосредственно.

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

+7

Я не нахожусь над моей головой, я новичок. Во-первых, мой селектор fillPickerView вызывается, если школы не ноль, как указано: if (! (Self.schools == nil)). Очевидно, мне нужно использовать GCD, так что спасибо за этот совет. В общем, я не думаю, что нужно вызывать людей за то, что они были над ними, люди здесь, чтобы учиться. – angerboy

+0

Это старый поток, но я только что видел ваш ответ. Я не хотел быть оскорбительным, и я извиняюсь, если это так. Параллелизм - это продвинутая тема, и есть бесчисленные способы, которыми вы можете стрелять в ногу (несколько раз одновременно, даже.) Я бы посоветовал не заниматься дайвингом в параллельном программировании, пока у вас не будет опыта на начальном уровне. Это похоже на попытку летать соло 747, когда вы все еще изучаете основы детеныша пипец. –

Смежные вопросы