1

私が理解しているように、スレッドで実行されるタスクを送信するにはいくつかの方法があります。私が使用する最も一般的なものは次のとおりです。

1) performSelector:withObject:afterDelay:

2) performSelectorOnMainThread:withObject:waitUntilDone:

3) performSelectorInBackground:withObject:

4) [NSThread detachNewThreadSelector:toTarget:withObject:]

私の最初の質問は、明らかなパラメーターの違い以外に、1) と 2) の違いは何ですか? どちらも実際にメイン スレッドで動作していますか (その自動解放プールは main.m で自動的に作成されました)。Stackoverflow に関する誰かの投稿から、メソッド 1) が実際に新しいスレッドで動作していることを読んだところです。そのため、そのセレクター メソッド用に自動解放プールを作成する必要があります。これは正しいです?私は主に遅延パラメーターを利用するために 1) を多く使用してきましたが、それらの自動解放プールを作成したことはありません。壊滅的なことは何も起こっていません。

次に、3) と 4) はどちらも別のスレッドでタスクを実行します。これらのスレッドで UI の処理を​​行うべきではないと聞きましたが、厳密に UI とは何かについて混乱しています。テーブルビューがナビゲーションコントローラーからモーダルに起動している間に、基本的に繰り返し読み込みアニメーションを再生するコードを作成しようとしていました。アニメーションは、tableview コントローラーの viewDidLoad メソッドで停止されます。最初は、モーダル ビューを開始するコード行の上に、アニメーションを開始するコードを貼り付けました。何が起こったかというと、アニメーションはまったく再生されませんでした。

[[self loadingView] playAnimation];

SettingsViewController *menus = [[SettingsViewController alloc] initWithNibName:@"SettingsViewController" bundle:nil];

MyNavigationController *navController = [[MyNavigationController alloc] initWithRootViewController:menus];

[menus setParent:navController];
[navController setDelegate:self];
menus.mainViewController = self;

[self presentModalViewController:navController animated:YES];
[navController release];
[menus release];

次に、次のことを試しましたが、うまくいきました...

[NSThread detachNewThreadSelector:@selector(settingsOpeningThread) toTarget:self withObject:nil];
[[self loadingView] playAnimation];



- (void) settingsOpeningThread {

NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];

SettingsViewController *menus = [[SettingsViewController alloc]   initWithNibName:@"SettingsViewController" bundle:nil];

MyNavigationController *navController = [[MyNavigationController alloc] initWithRootViewController:menus];

[menus setParent:navController];
[navController setDelegate:self];
menus.mainViewController = self;

[self presentModalViewController:navController animated:YES];
[navController release];
[menus release];

[apool release];

}

アニメーションは、SettingsViewController ビューが完全に起動されるまで再生を続けます。しかし、このようなモーダル ビューの起動は「UI」としてカウントされ、避けるべきでしょうか? また、モーダル ビューが起動されるたびに、Instruments で奇妙なメモリ リーク エラーが発生します。しかし、それはデバッグが非常に難しいと言われている「システム ライブラリ」の 1 つからのものです。ここで何がうまくいかないのでしょうか?

恥ずかしいほどの長文で申し訳ありません。どんな助けでも大歓迎です!

4

1 に答える 1

1

(1)現在の runloopのタスクをスケジュールします。非常に高いレベルでは、UIKit アプリケーションは次のようになります。

while(true) {
  update UI
  run all tasks that were scheduled last time through the loop
}

これが、最初の試行で UI が更新されなかった理由です。への呼び出し playAnimationは、runloop の次の繰り返しで UI が更新されるようにスケジュールしますが、それに続くコードが完了するまでそこに到達することはありません。

別のスレッドで指定されたコードを実行performSelector:withObject:afterDelayしないことに注意してください。

(2) は非常によく似た処理を行いますが、現在の実行ループに対して何かをスケジュールするのではなく、メイン スレッドの実行ループに対して何かをスケジュールします。これは、通常、セカンダリ スレッドから UI を更新する必要があるため、別のスレッドから呼び出された場合にのみ役立ちます。

はい、あなたのコードは少し太字です。次のようなことをお勧めします:

[[self loadingView] playAnimation];
[self performSelector:@selector(loadTable) withObject:nil afterDelay:0]

テーブルをロードする実際のコードは にありloadTableます。これは、ランループが発生すると、UI が更新され、アニメーションの再生が開始され、メソッドloadTable呼び出されてそのジョブを実行することを意味します。

ただし、アニメーションの実行にメイン スレッドからの介入が必要な場合は、これでも機能しません。つまり、テーブルをロードするコードがメイン スレッドを停止させると、アニメーションも停止する可能性があります。別のスレッドで長期実行タスクを実行する以外に、これを回避する方法はありません (performSelector:onMainThread:waitUntilDoneメイン スレッドで UI の更新をスケジュールするために使用される場合と使用されない場合があります)。

アニメーション自体をあまり気にしない場合は、https://github.com/samvermette/SVProgressHUDのようなものが役立つかもしれません。

于 2011-10-10T09:05:55.417 に答える