2013-12-15 17 views
5

performSelectorOnMainThreadを使用してUIを更新する際に問題が発生しました。ここに私の状況があります。私のviewDidLoadでは、アクティビティインジケータとラベルを設定しました。次に、セレクタを呼び出してサーバーからデータを取得します。次に、遅延の後にUIを更新するセレクタを呼び出します。ここでは、コードは次のとおり目的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は、データが取得されたかどうかを調べ、それに応じて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を更新しようとしていない理由を私に説明することはできますか?

+0

することができます[GCD](http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html)を使用して、他のスレッドにデータをディスパッチし、メインスレッドのUIを更新します。 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を使用して、固定遅延20秒後にメインスレッド上でメソッドupdateUIを実行します。

updateUIは、あなたのバックグラウンドスレッドによって設定されていると思われるself.schoolsをチェックし、実行される場合とされない場合があります。 self.schoolsがnilの場合、performSelectorOnMainThreadを使用してfillPickerViewを呼び出します。それは理にかなっていません。なぜなら、self.schoolsが無ければ、ピッカーを埋めるデータがないからです。

self.schoolsがnilでない場合は、performSelectorOnMainThreadを使用してエラーを表示します。

self.schoolsのあなたの小切手のロジックが後方にあるようです。それが無ければ、エラーを表示する必要があり、それがnilでない場合は、ピッカーを記入する必要があります。

次の問題:どちらの場合でも、performSelectorOnMainThread:withObject:waitUntilDone:をメインスレッドから呼び出しています。メインスレッドからそのメソッドを呼び出すことは意味がありません。

第3の問題:バックグラウンドタスクが完了するまで任意の時間待ってから、成功または失敗します。 20秒間何が起こっているのか分かりません。バックグラウンドタスクがより早く終了する場合、あなたは決して知らないでしょう。

代わりに、タスクが完了したらバックグラウンドタスクにメインスレッドに通知する必要があります。それはperformSelectorOnMainThread:withObject:waitUntilDone:の有効な使用であり、メインスレッドから呼び出している間はそうではありません。 (ここでも、しかし、あなたは直接スレッドを使用していない、GCDを使用するには、このコードをリファクタリングする必要があります。

あなたの頭の上にあることをかなり明確ようだ。あなたは完全に書き換える必要があるが掲示コード。

+7

私は頭の中ではない、私は初心者です。まず、私のfillPickerViewセレクタは、学校がnilでない場合に呼び出されます:if(!(self.schools == nil))によって与えられます。明らかに私はGCDを使う必要があるので、そのヒントをありがとう。一般的に私は人々を頭の中にいることを人々に呼び出す必要はないと考えています。人々はここで学びます。 – angerboy

+0

これは古いスレッドですが、私はあなたの応答を見ました。私は侮辱するつもりはなかったし、そういうふうに思えば謝る。並行処理は高度なトピックであり、足で自分自身を撃つことができる無数の方法があります(複数回、同時に)。初心者レベルの経験以上になるまで、並行プログラミングへの潜入を勧めます。それはあなたがまだパイパーの子の基礎を学んでいるときに747のソロを飛ばすようなものです。 –

関連する問題