0

こんにちは、よろしくお願いします。あるビューでを開始してNSTimerから で別のビューに切り替えると、UIPickerViewUIPickerView動作が影響を受けるという問題があります。任意のビューと を含むビューの間を行き来するNSTimerほど、 の動作に深刻なUIPickerView影響が及びます。それらは遅れて動きが鈍くなり、最終的に がメソッドUIPickerViewを呼び出さないポイントに到達します。影響を受けているDidSelectRowのは 1 つだけではなく、私のアプリのすべてです。UIPickerViewUIPickerView

NSTimerそもそもをアクティベートしないことにした場合UIPickerViews、問題なく動作します。ただし、メソッドを呼び出すと、を含むビューと他のビューNSTimerの間で 6 回前後に切り替えた後、アプリはすべて完全に動作しなくなります。適切な動作を復元するには、アプリをシャットダウンして再起動する必要があります。NSTimerUIPickerView

私は使用してARCいるので、手動でリリースしていませんが、NSTimerこれは私の問題と関係があると思います。. . NSTimer_ とにかく、これは何かをコーディングする 2 回目の作業なので、この問題を修正する方法がわかりません。 とが同じまたはスレッドを介して割り当てられる可能性があることNSTimerを読んだことがNSTimerありますが、それが何を意味するのかはよくわかりません。UIPickerViewNSRunLoop

とにかく、ここに私のコードがあります - そのかなり一般的なボイラープレートコードです。

-(void)showActivity:(NSTimer *)tim {

    NSDate *currentDate = [NSDate date];
    NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];
    NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];

    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"HH:mm:ss.S"];
    [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
    NSString* timeString = [dateFormatter stringFromDate:timerDate];
    stopWatchLabel.text = timeString;

}


- (IBAction)onStartPressed:(UIButton *)sender; {

    stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1/10
                                                  target:self
                                                selector:@selector(showActivity:)
                                                userInfo:nil
                                                 repeats:YES];
    // Save the new start date every time
    startDate = [[NSDate alloc] init]; // equivalent to [[NSDate date] retain];
    NSDate *savedMentionDate = [[NSUserDefaults standardUserDefaults] objectForKey:@"mostRecentMentionDate"];

    if (savedMentionDate == nil) {
        //There is no existing mention, so save the most recent one
        [[NSUserDefaults standardUserDefaults]setObject:startDate forKey:@"mostRecentMentionDate"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    } else {
        startDate = savedMentionDate;
    }

    [stopWatchTimer fire];

    timerSetting = 0;

    NSNumber* timerSettingNS = [[NSNumber alloc] initWithInt:timerSetting];
    [[NSUserDefaults standardUserDefaults] setObject:timerSettingNS forKey:@"timerSetting"];
    [[NSUserDefaults standardUserDefaults] synchronize];

}


- (IBAction)onStopPressed:(UIButton *)sender {

    [stopWatchTimer invalidate];

}


- (IBAction)resetTimer:(UIButton *)sender; {

    stopWatchLabel.text = @"00:00:00.0";

    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
    [defaults removeObjectForKey:@"mostRecentMentionDate"];

    timerSetting = 1;

    NSNumber* timerSettingNS = [[NSNumber alloc] initWithInt:timerSetting];
    [[NSUserDefaults standardUserDefaults] setObject:timerSettingNS forKey:@"timerSetting"];
    [[NSUserDefaults standardUserDefaults] synchronize];

}

-(void)ViewDidLoad {
    ...
    ...
    NSNumber* timerSettings = [defaults objectForKey:@"timerSetting"];

    if (timerSettings == nil || timerSettings.intValue == 1) {

        [self resetTimer:resetTime];

    } else if (timerSettings.intValue == 0) {

        [self onStartPressed:start];

    }

}
4

2 に答える 2

0

私は解決策を見つけました。アプリがビューを切り替えることができるようにするすべてのメソッドにコード[stopWatchTimerinvalidate]を挿入しました。

これは多かれ少なかれ誰もがあなたに言ったことでしょう:

viewDidLoadメソッドとviewDidUnloadメソッドに[stopWatchTimerinvalidate]を含めても効果がなかったため、これが機能することに驚いています...

これらのメソッドは、非常に特定の場合にのみ呼び出されます。

viewDidLoadビューコントローラのビューがロードされたときに呼び出されます。(それほど驚くべきことではありません…)

load重要な部分は、次の意味を理解することです。

ビューコントローラがインスタンス化されると(NIBからであれ、コード内であれ)、ビューはありません。代わりに、それが持っているのは、それを求められたときに、それをどのように提供するかについての情報です。

したがって、viewメッセージをUIViewControllerに送信すると、_viewインスタンス変数がすでに設定されているかどうかが判断されます。そうでない場合は、独自のloadViewメソッドを呼び出します。このメソッドは、そのインスタンス変数を意味のあるもので埋めるために必要なことをすべて実行します。次に、viewDidLoadメッセージを送信して、管理するビュー階層の設定を完了します。その後、の値が返されます_view

これviewDidLoadは、ビューコントローラのビューの存続期間中に一度だけ呼び出されることを意味します。しかし、それはどういう意味ですか?

iOS 5以前では、ビューの存続期間は、表示されているビュー階層の一部であることに関連していました。ビューがビュー階層に含まれておらず、所有するビューコントローラーがメモリ警告を受け取った場合、基本実装は基本的にビューがビューかどうかを確認します。スーパービューがあり、(そうでない場合は)呼び出しviewWillUnload、解放、および無効にし_view、最終的に呼び出しviewDidUnloadてこのプロセスを終了します。(そのため、一部のくだらないレガシーコードベースでは、そのオーバーライドがdidReceiveMemoryWarning呼び出されない場合がありますsuper…)

iOS 6以降、UIViewControllerはこれを実行しなくなりました。

そのため、viewWillUnloadおよびviewDidUnloadは非推奨になりました。ビューは、所有しているView Controllerが破棄されるまで存続するため、これらのメソッドは呼び出されなくなります。

それが邪魔にならないように、あなたのタイマーをクリアするための関連する状況は何ですか?1.viewWillDisappear:ビューが「ステージを離れる」ところなので、前面と中央にある場合にのみ関連するものをすべて破棄します。2.タイマーの影響を受ける部分を隠す場合はいつでも。これは、別のView Controllerを表示している、またはUIPickerViewなど、画面の大部分をその下に非表示にしている他のものを表示していることが原因である可能性があります。3.タイマーを再構成/リセットする必要があるときはいつでも。(これを怠ったことが、アプリがそもそも急停止した理由です。)

これらの問題に関する優れたドキュメントがXcode内からオンラインで入手できます。

  • View Contollerプログラミングガイドは、iOSのすべてのものにとって絶対に読まなければならないものです。
  • NSTimerクラスリファレンス、およびリンクされたコンパニオンガイドは非常に優れています。「タスク」セクションの前に、概念的な部分を必ず読んでください。NSTimerタグの下で尋ねられる(そして実際にはNSTimerに関連する)質問の90%をはるかに超えて、人々が実際にこれを読んだかどうかは尋ねられません…</ li>
于 2012-12-27T10:41:02.860 に答える
0

私は解決策を考え出しました。アプリがビューを切り替えられるようにするすべてのメソッドに、コード [stopWatchTimer invalidate] を挿入しました。[stopWatchTimer invalidate] を viewDidLoad および viewDidUnload メソッドに含めたとき、何の効果もなかったので、これが機能することに驚いています...

于 2012-12-27T08:33:07.890 に答える