0

作業中のアプリの時計を作成しました。通常の時計から始まりますが(毎回1秒ずつカウント)、2秒ごと、4秒ごと、8秒ごとなど、20に達してアプリがクラッシュするまでフリーズします。 、xcodeの表示にエラーはなく、。もありませんRecieved Memory Warning

Instrumentsに行ったところ、時計を使用しているときに、アプリのメモリが驚くべき速度で増加していることがわかりました(ただし、どの速度でも驚くべき速度で増加しています)。問題は、メモリが非常に高くなる原因が正確に何であるかを理解できないことです。アプリはARCで実行されているので、何かをリリースすることを忘れなかったことを知っています。私が考えることができる唯一のことは、番号がロードされるたびに、それはメモリに保存され、決して解放されないということです。それがどういうことか、私にはわからない、そしてそれを修正する方法は私にはさらに少ない考えがあります。何ができるか教えてください。これが私のコードです:

-(void)updateTime {

    calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
    updateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime) userInfo:nil repeats:YES];

    currentTime = [NSDate date];
    dateComponents = [calendar components:unitFlags fromDate:currentTime];
    year = [dateComponents year];
    month = [dateComponents month];
    day = [dateComponents day];
    hour = [dateComponents hour];
    minute = [dateComponents minute];
    second = [dateComponents second];

    if (hour >= 12) {
        lblAMPM.text = @"PM";
    } else {
        lblAMPM.text = @"AM";
    }

    //if (isTwelveHour == YES) {
        //make a 12 hrs clock instead of 24
        if (hour >= 12) {
            hour = 12 - (24-hour);
        }
    //}

    //if midnight, show hour as 12 instead of 0
    if (hour == 0) {
        hour = 12;
    }

    if (second < 10) {
        seconds = [NSString stringWithFormat:@"0%i", second];
    } else {
        seconds = [NSString stringWithFormat:@"%i", second];
    }

    if (minute < 10) {
        lblTime.text = [NSString stringWithFormat:@"%i:0%i:%@", hour, minute, seconds];
    } else {
        lblTime.text = [NSString stringWithFormat:@"%i:%i:%@", hour, minute, seconds];
    }

    [lblDate setText:[NSString stringWithFormat:@"%d/%d/%d", month, day, year]];

}

- (void) updateDateFirst:(int)firstComponent setSecond:(int)secondComponent{

    calendar = [NSCalendar currentCalendar];
    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
    updateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime) userInfo:nil repeats:YES];

    currentTime = [NSDate date];
    dateComponents = [calendar components:unitFlags fromDate:currentTime];
    year = [dateComponents year];
    month = [dateComponents month];
    day = [dateComponents day];

    [lblDate setText:[NSString stringWithFormat:@"%d/%d/%d", firstComponent, secondComponent, year]];

}

- (void)viewDidUnload {
    lblTime = nil;
    lblAMPM = nil;
    lblDate = nil;
    [super viewDidUnload];
}

参考までに、私は電話をかけupdateTimerviewDidAppearいます。

4

2 に答える 2

2

が呼び出されるNSTimerたびに、新しいオブジェクトを作成します。updateTimeしたがって、割り当てられて実行中のタイマーの数は、毎秒 2 倍に増加します。

  • 1 秒後にupdateTimeが呼び出され、新しいタイマーが作成されます。ただし、オプションがあるため、最初のタイマーは実行され続けrepeats:YESます。
  • 次の 1 秒後、両方のタイマーが作動し、 を呼び出しますupdateTime。これでタイマーが 4 つになりました。
  • 等々 ...

あなたの目的はわかりませんがupdateDateFirst:、別のタイマーが作成されます。

そのため、タイマーは 1 回だけ作成する必要がありますviewDidAppearinvalidateまた、タイマーを ( を使用して)停止することを忘れないでくださいviewWillDisappear

于 2012-08-14T06:54:17.473 に答える
2

が呼び出されるたびupdateTimeに、新しいタイマーが作成され、呼び出し時に現在の実行ループに追加されます。

updateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime) userInfo:nil repeats:YES];

実行ループはこれらのタイマーを保持します。したがって、NSTimerivarが指すものを置き換え続けても、updateTimerそれらは決してdealloc編集されません。ARC はNSTimer割り当てられたそれぞれを管理しupdateTimer、それらにマッチングretain/releaseコールを持たせます。ただし、最初に追加されたときのby the run ループは、タイマーが繰り返されて無効化されないためretain、マッチングとペアになることはありません。releaseしたがって、シーケンスは次のようになります。

  1. を呼び出し- (void) updateDateFirst:(int)firstComponent setSecond:(int)secondComponentて開始すると、NSTimer.
  2. このタイマーは 1 秒後に起動updateTimeし、新しいタイマーを作成する を呼び出します。元のタイマーが繰り返されているため、1 秒後に再び発火します。これでタイマーが 2 つになりました。
  3. 両方のタイマーが約 1 秒後に起動し、 を呼び出しupdateTimeて、2 つの新しいタイマーを作成します。これでタイマーが4つになりました....

これを行う標準的な方法は、 の各呼び出しではなく、最初に 1 つの繰り返しタイマーを作成することupdateTimerです。完了したら、次のように呼び出します。

[updateTimer invalidate];
upateTimer = nil;

これにより、タイマーが停止して解放されます。

于 2012-08-14T06:55:12.363 に答える