Ios 目标C-在主线程上更新UI时出现问题
使用performSelectorOnMainThread更新UI时遇到问题。这是我的情况。在我的viewDidLoad中,我设置了一个活动指示器和一个标签。然后我调用选择器从服务器检索一些数据。然后,我调用选择器在延迟后更新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
- (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单飞一样。