2011-12-28 6 views
2

私はiPhone開発の初心者です。特に、私はオンラインのmysqlデータベースからのデータで電話機のsqliteデータベースを更新する更新機能を書いていました。アップデート自体はうまくいきましたが、アップデートが完了するまでUIはフリーズしました。正しい方法でマルチスレッドを実行します

これは実際にはあまりにも大したことではありませんが、電話アプリが更新中であっても(ボタンは青色のまま押されていて、その上のテキストは「更新中」に変更されました。その上にあるテキストメッセージが更新しているように見える)、一部の人々はまだそれが更新されていることを知らなかった...だから私はそれを自身のスレッドに入れて、 (マルチスレッド化せずに画像を入れても画像が凍ってしまうので)

私の問題は、アプリケーションを「一時停止」している間にスレッドを開始する(ユーザーが他のページなどに移動することを許可しない)適切な方法を知らず、完了時にアプリケーションを「一時停止」します。

私は実際にはこの機能を持っていますが、シミュレータでのみ使用できます。 iTunesにアップロードして承認した後にダウンロードした後は、動作しません。アプリケーションは永久に一時停止されます。 、

- (IBAction)update:(id)sender{ 
    [NSThread detachNewThreadSelector:@selector(doUpdate:) toTarget:[UpdateViewController class] withObject:nil]; 

    canGo = FALSE; 

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(threadDone:) name:NSThreadWillExitNotification object:nil]; 

    while (!canGo){ 
    } 

    [activity stopAnimating]; 
    activity.hidden = YES; 
    status_text.text = @"Update Successful! You may have to close and restart the app."; 
} 

あなたがここに見ることができるように、私は別のスレッドを作成し、その後whileループは無限に行われてから、他のすべてのプロセスを保持している:更新プロセスを開始し

メインスレッド、:ここに私の現在のコードですユーザーはプログラム内をナビゲートできません。 (私は間違っているはずですが、これを行う正しい方法の例は見つけられません)。この関数が呼び出される前は、処理イメージのアニメーションが開始されます。 (そして、はい、私はこれらが技術的に「機能」ではないことを知っていますが、間違った用語を言い訳してください)。 :

+ (void)doUpdate:(id)param{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; 

    // Stuff happens here 

    UpdateViewController *talkThread = [[UpdateViewController alloc] init]; 
    [talkThread threadDone:nil]; 

    [pool drain]; 
} 

、別の関数が両方によって呼び出される(シミュレータ上で動作しますが、これではないの後にiTunesのダウンロード):私も「threadDone」を呼び出すコードをコメントアウトしようとした

-(void)threadDone:(NSNotification*)arg { 
    NSLog(@"Exiting"); 
    canGo = TRUE; 
} 

私の新しいスレッドでは、私は使用しました:

threadDoneとまったく同じことをした、新たな機能を持つ
[self performSelectorOnMainThread:@selector(finishLoop) withObject:nil waitUntilDone:FALSE]; 

-(void)finishLoop{ 
    NSLog(@"Finish Loop"); 
    canGo = TRUE; 
} 

これはまったく何もしませんでした。デバッガでは、私がアップデートを進めていったときにfinishLoopが全く呼び出されませんでした。しかし、私は "performSelectorOnMainThread"行にエラーがないので、何が間違っているのか分かりません。

UIを停止せずに一時停止する別のスレッドを設定する正しい方法を説明してくれている人に感謝します(「ホテルが更新されました」などのテキストを表示できるようにするか、プレースメントがフリーズすることはありません)、更新が完了した後でUIを一時停止します。これはかなりの間今の痛みだったので、事前にありがとうございました。

答えて

2

ユーザーがUIとやりとりするのを防ぐには、[[UIApplication sharedApplication] beginIgnoringInteractionEvents]に電話してください。ユーザーが再び対話することができる場合は、endIgnoring...に電話してください。

EDIT:スレッドの終了時に何かを呼び出す方法について尋ねました。 GCDスレッドのアーキテクチャは次のようになります。

dispatch_async(my_queue, ^{ 
    // ... do stuff in a background thread ... 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     // ... the thread is over, do stuff on the main thread ... 
    }); 
}); 

本当に簡単です。

+0

これはいいようですが、スレッドが終了したら何かを正しく呼び出す方法がわかりません。それはシミュレータ上で動作するようですが、iTunesからダウンロードした後ではありません。 – James

+0

さて、ステップ1では、そのすべての 'detachNewThreadSelector:'を使用していません。このような状況がグランドセントラルディスパッチに恵まれている理由です。そのため、スレッドが終了したときにメインスレッドで何かを呼び出すことが非常に簡単になります。 – matt

+0

さて、 "myqueue"変数の設定方法がわかりませんでしたが、 'dispatch_queue_t my_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT、0);'のように設定しました。最初のキューに入るときにエラーは発生しませんが、 'dispatch_async(dispatch_get_main_queue()、^ {')は入力されず、その間にコードは実行されません。 – James

1

バックグラウンドで作業しているときにユーザがどこにも行かないようにするには、各UIControl(UIButton、UITextFieldなど)でenabledプロパティを設定するか、UI全体に透明UIViewをオーバーレイしてブロックしますタッチイベント。無限ループは決して正しい答えではありません。それらを使用する効果は、バックグラウンドスレッドを使用する目的を無効にします。特定のユーザーアクションがある場合は、更新中にブロックする方法がわからない場合は、コメントに投稿してください。

+0

私はユーザーに何もできないようにしたくありません。 UIのフリーズは、実際には私にはうまくいきました。しかし、アップデートが進行中であることを示すためにアニメーション化されたイメージを置く必要があるので、私はもうUIをフリーズできません。 – James

1

MBProgressHUDを使用して、いくつかの作業を保存できます。 これはあなたのニーズにちょうど適合します。バックグラウンドで作業中にプロセスインジケータを表示します。

+0

しかし、コード内にフラグを立てるだけの完全なクラスを含めることが本当に必要でしょうか?余分な通知は必要ありません。スレッドがいつ終了するかを知りたいだけです。 – James

1

MBProgressHUDフレームワークを見ましたか?オープンソースであり、あなたが探しているものを満たすようです。

MBProgressHUDは、バックグラウンドスレッドでの作業中に進行状況インジケータといくつかのオプションのラベルが付いた半透明のHUDを表示するiPhoneドロップインクラスです。 HUDは、文書化されていないプライベートUIKit UIProgressHUDの代わりに、いくつかの追加機能を備えています。