Ios 目标C-在主线程上更新UI时出现问题

Ios 目标C-在主线程上更新UI时出现问题,ios,objective-c,user-interface,Ios,Objective C,User Interface,使用performSelectorOnMainThread更新UI时遇到问题。这是我的情况。在我的viewDidLoad中,我设置了一个活动指示器和一个标签。然后我调用选择器从服务器检索一些数据。然后,我调用选择器在延迟后更新UI。代码如下: - (void)viewDidLoad { [super viewDidLoad]; self.reloadSchools = [[UIAlertView alloc] init]; self.reloadSchools.messa

使用performSelectorOnMainThread更新UI时遇到问题。这是我的情况。在我的viewDidLoad中,我设置了一个活动指示器和一个标签。然后我调用选择器从服务器检索一些数据。然后,我调用选择器在延迟后更新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检查数据是否已检索,并在主线程上调用选择器以相应地更新UI。以下是这些部件的代码:

-(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吗?

首先,您不应该使用detachNewThreadSelector。您应该使用GCD并将后台任务提交到异步队列。创建线程的成本很高。GCD在管理系统资源方面做得更好

dispatch_async(dispatch_get_global_queue(0, 0), ^{
 //load your data here.
 dispatch_async(dispatch_get_main_queue(), ^{
                //update UI in main thread.
            });
});
忽略这一点,你的代码对我来说没有多大意义。提交一个方法getSchoolList,在后台线程上运行。您不会显示正在后台运行的代码

然后使用performSelector:withObject:afterDelay在20秒的固定延迟后在主线程上运行updateUI方法

updateUI检查self.schools,它可能是由您的后台线程设置的,可能是也可能不是。如果self.schools为nil,则使用performSelectorOnMainThread调用fillPickerView。这是没有意义的,因为如果self.schools为零,则没有数据可以填充选择器

如果self.schools不是nil,则再次使用performSelectorOnMainThread显示错误

在我看来,你检查自我学校的逻辑是倒退的。如果为nil,则应显示错误,如果不是nil,则应填充选择器

下一个问题:在这两种情况下,都是从主线程调用performSelectorOnMainThread:withObject:waitUntilDone:。从主线程调用该方法没有意义

第三个问题:等待后台任务运行到完成,然后等待成功或失败,这是没有意义的。在整整20秒内,你根本不知道发生了什么。如果后台任务完成得更快,你永远不会知道

相反,您应该让后台任务在任务完成后通知主线程。这将是performSelectorOnMainThread:withObject:waitUntilDone:的有效用法,而从主线程调用它则不是。(不过,您还是应该重构此代码以使用GCD,而不是直接使用线程


很明显,你是在胡思乱想。你发布的代码需要完全重写。

你可以使用在另一个线程上发送数据并在主线程中更新UI,这比使用NSThread要好。我不是在胡思乱想,我是一个初学者。首先,如果schools不是nil,我的fillPickerView选择器将被调用,如前所述作者:if(!(self.schools==nil))。显然,我需要使用GCD,所以谢谢你的提示。一般来说,我认为没有必要因为人们的头脑不清醒而叫出声来,人们是来学习的。这是一条古老的线索,但我刚刚看到了你的回答。我不是有意侮辱,如果是这样的话,我道歉。并发是一个高级主题,而且有很多问题我建议,在你拥有超过初学者水平的经验之前,不要涉足并发编程。这就像你还在学习琵琶幼崽的基础知识时尝试驾驶747单飞一样。