0

UIViewによって作成されたキューを介してサブビューを作成および追加するコードがいくつかありまし[[NSOperationQueue alloc] init]たが、奇妙な動作の遅延につながりました。サブビューは、異常に長い遅延の後にのみ追加されました。

[NSOperationQueue mainQueue]しかし、その後、これらの部品に使用するように切り替えたところ、応答性は正常になりました。

最初のアプローチを使用して見た遅延動作の説明が欲しいだけです。

4

1 に答える 1

2

アップルのドキュメントから

スレッドとユーザー インターフェイス

アプリケーションにグラフィカル ユーザー インターフェイスがある場合は、ユーザー関連のイベントを受け取り、アプリケーションのメイン スレッドからインターフェイスの更新を開始することをお勧めします。このアプローチは、ユーザー イベントの処理とウィンドウ コンテンツの描画に関連する同期の問題を回避するのに役立ちます。Cocoa などの一部のフレームワークでは通常、この動作が必要ですが、そうでないフレームワークでも、メイン スレッドでこの動作を維持すると、ユーザー インターフェイスを管理するためのロジックが簡素化されるという利点があります。他のスレッドからグラフィカル操作を実行する方が有利な、注目すべき例外がいくつかあります。たとえば、QuickTime API には、ムービー ファイルを開く、ムービー ファイルをレンダリングする、ムービー ファイルを圧縮する、イメージをインポートおよびエクスポートするなど、セカンダリ スレッドから実行できる多くの操作が含まれています。同様に、Carbon および Cocoa では、セカンダリ スレッドを使用して画像を作成および処理し、その他の画像関連の計算を実行できます。これらの操作にセカンダリ スレッドを使用すると、パフォーマンスが大幅に向上します。ただし、特定のグラフィカル操作についてよくわからない場合は、メインスレッドから実行することを計画してください

さらに、スレッド プログラミング ガイドによると、UI クラスはスレッドセーフではありません。

そのため、メイン スレッドとは異なるスレッドから UI を更新することは避けてください。

(キュー内で) を実行NSOperationすると、次のようなメイン スレッドでメソッドを実行して UI を更新できます (たとえば、アプリのライフサイクルに必要なデータをダウンロードした後)。

-(void)main {

    // e.g the delegate could be the controller that has the view that you want to update
    if (delegate) {

        NSURL *url = [delegate urlForDownloadOperation:self];
        if ( nil == url ) return;
        self.downloadedImage = [[NSImage alloc] initWithContentsOfURL:url];
        
        // e.g. rather than invoking processImage directly on the delegate, ensure that the method draw the image on the main thread
        [delegate performSelectorOnMainThread:@selector(processImage:) 
            withObject:self waitUntilDone:YES];
    }
}

または、次のように UI を更新する必要があるコンポーネントに通知を送信できます。

- (void)main {

   NSURL *url = [delegate urlForDownloadOperation:self];
   if ( nil == url ) return;
   self.downloadedImage = [[NSImage alloc] initWithContentsOfURL:url];
   
   // e.g. send a notificatio to inform some components that it is ready to update the UI with some content
   [[NSNotificationCenter defaultCenter] postNotificationName:@"importData" object:self];
}

UI を更新する必要があるコンポーネントは、次のようにその通知を登録します。

- (void)processImage:(NSNotification*)notification
{
    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(processImage:) withObject:notification waitUntilDone:YES];
        return;
    }

    // update the UI here, you are running on the main thread
}
于 2012-07-10T20:43:26.793 に答える