2

インターネットからZIPファイルをダウンロードできます。後処理はconnectionDidFinishLoadingで実行され、UIView要素が更新されないことを除いて正常に機能します。たとえば、statusUpdate.text = @ "Uncompressing file"を設定しましたが、その変更は、connectionDidFinishLoadingが完了するまで表示されません。同様に、UIProgressViewオブジェクトとUIActivityIndi​​catorViewオブジェクトは、このメソッドが終了するまで更新されません。

このメソッド内からUIViewの更新を強制する方法はありますか?[self.view setNeedsDisplay]を設定しようとしましたが、うまくいきませんでした。メインスレッドで実行されているようです。ここにある他のすべてのコマンドは問題なく機能します。唯一の問題はUIの更新です。

ありがとう!

更新:UIVIEWを更新しないコードは次のとおりです。

-(void)viewWillAppear:(BOOL)animated {
    timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(processUpdate:) userInfo:nil repeats:YES];
    downloadComplete = NO;
    statusText.text = @"";

}

-(void)processUpdate:(NSTimer *)theTimer {
    if (! downloadComplete) {
        return;
    }

    [timer invalidate];
    statusText.text = @"Processing update file."; 
    progress.progress = 0.0;
        totalFiles = [newFiles count];
    for (id fileName in newFiles) {
        count++;
            progress.progress = (float)count / (float)totalFiles;
        // ... process code goes here ...
         }
}

次に、processUpdateの最後に、downloadComplete=YESを設定します。これはエラーなしでビルドおよび実行され、processUpdateが完了するまでUIVIEWで何も更新されないことを除いて、意図したとおりに機能します。その後、すべてが一度に更新されます。

これまでのご協力に感謝します!

4

5 に答える 5

1

Nielsが言ったように、ビューの更新を確認するには、制御を実行ループに戻す必要があります。ただし、本当に必要な場合を除いて、新しいスレッドのデタッチを開始しないでください。私はこのアプローチをお勧めします:

- (void)connectionDidFinishLoading:(NSConnection *)connection {
    statusUpdate.text = @"Uncompressing file";
    [self performSelector:@selector(doUncompress) withObject:nil afterDelay:0];
}

- (void)doUncompress {
    // Do work in 100 ms chunks
    BOOL isFinished = NO;
    NSDate *breakTime = [NSDate dateWithTimeIntervalSinceNow:100];
    while (!isFinished && [breakTime timeIntervalSinceNow] > 0) {
        // do some work
    }
    if (! isFinished) {
        statusUpdate.text = // here you could update with % complete
        // better yet, update a progress bar
        [self performSelector:@selector(doUncompress) withObject:nil afterDelay:0];
    } else {
        statusUpdate.text = @"Done!";
        // clean up
    }
}

基本的な考え方は、小さなチャンクで作業することです。メソッドから戻って、実行ループを定期的に実行できるようにします。PerformSelector:を呼び出すと、最終的にコントロールがオブジェクトに戻ることが保証されます。

これを行うリスクは、ユーザーがボタンを押したり、予期しない方法でUIを操作したりする可能性があることに注意してください。作業中に入力を無視するようにUIApplicationを呼び出すと役立つ場合がありますbeginIgnoringInteractionEvents...本当に素晴らしく、メソッドにチェックインするフラグを設定するキャンセルボタンを提供したい場合を除きますdoUncompress...

自分で実行ループを実行して、[[NSRunLoop currentRunLoop] runUntilDate:...]頻繁に呼び出すこともできますが、自分のコードで試したことはありません。

于 2010-01-08T20:12:45.627 に答える
0

connectionDidFinishLoadingを使用している間、アプリケーションの実行ループでは他に何も起こりません。UIの更新を調整できるように、制御を実行ループに戻す必要があります。

データ転送に完了のフラグを付け、ビューを更新するだけです。ダウンロードしたデータの重い処理は、それ自体のスレッドに延期します。

アプリケーションはビューをコールバックして、実行ループの後半でコンテンツを更新できるようにします。必要に応じて、独自のカスタムビューにdrawRectを実装します。

于 2010-01-03T10:36:11.443 に答える
0

メインスレッドでconnectionDidFinishLoadingを受信して​​いる場合は、運が悪いです。このメソッドから戻らない限り、UIでは何も更新されません。

一方、別のスレッドで接続を実行する場合は、次のコードを使用してUIを安全に更新できます。

UIProgressView *prog = ... <your progress view reference> ...
[prog performSelectorOnMainThread:@selector(setProgress:)
                       withObject:[NSNumber numberWithFloat:0.5f]
                    waitUntilDone:NO];

非メインスレッドからUIを更新しないように注意してください-常にperformSelectorOnMainThreadメソッドを使用してください!

于 2010-01-08T07:28:28.263 に答える
0

タイマーで行っていることを正確に実行し、ConnectionDidFinish:を使用して処理コードを新しいスレッドにディスパッチするだけです。タイマーはメインスレッドから実行されるため、UIを更新できます。

于 2011-10-12T04:39:50.537 に答える
0

for()問題は、UIがループで更新されないことが判明しました。簡単な解決策については、このスレッドの回答を参照してください。

于 2012-12-09T18:09:42.443 に答える