Objective-C每天在给定时间执行方法 - 杂乱的实现

Jac*_*ins 0 iphone multithreading timer objective-c while-loop

我有以下(可见)方法不断检查当前时间,并且当达到特定时间(在这种情况下是午夜)时,NSLog语句运行一次以表示正在执行的有用的事情:

- (void) checkTime {

while (true){

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

    NSDate *now = [[NSDate alloc] init];

    NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];
    [outputFormatter setDateFormat:@"HH:mm"];

    NSString *nowDateString = [outputFormatter stringFromDate:now];

    if([nowDateString isEqualToString:@"00:00"]){
        NSLog(@"Store previous days data..");
        BOOL stillMidnight = YES;
        while(stillMidnight == YES){
            NSDate *latestNow = [[NSDate alloc] init];

            NSDateFormatter *latestOutputFormatter = [[NSDateFormatter alloc] init];
            [latestOutputFormatter setDateFormat:@"HH:mm"];

            NSString *latestString = [latestOutputFormatter stringFromDate:latestNow];
            //Check if it is still midnight
            if([latestString isEqualToString:@"00:01"]){
                //leave while
                stillMidnight = NO;
            }
        }
        NSLog(@"No longer midnight");
    }

    [loopPool drain];

}
Run Code Online (Sandbox Code Playgroud)

}

上面的方法从applicationDidFinishLaunchingWithOption方法调用如下:

[self performSelectorInBackground:@selector(checkTime) withObject:nil];
Run Code Online (Sandbox Code Playgroud)

这个代码在午夜运行一次NSLog(@"存储前几天数据......"),这是我需要的,但是这个问题有更优雅的解决方案吗?

谢谢,

插口

Tom*_*mmy 5

你会变得更好:

  1. 得到当前日期;
  2. 今天午夜时分锻炼身体;
  3. 在一天之后安排一次性计时器; 和
  4. 重复

很容易安排一个重复计时器,该计时器首先使用(3)和每24小时计算的日期触发,但这将无法实现夏令时.所以,例如(在这里直接编码,未经测试)

- (void)scheduleNextTimedAction
{
    // get the date now and the calendar the user is using
    // (which will include their time zone, helpfully)
    NSDate *dateNow = [NSDate date];
    NSCalendar *relevantCalendar = [NSCalendar currentCalendar];

    // decompose the current date to components; we'll
    // just ask for month, day and year here for brevity;
    // check out the other calendar units to decide whether
    // that's something you consider acceptable
    NSDateComponents *componentsForNow =
         [relevantCalendar components:
                  NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
                  fromDate:dateNow];

    // we could explicitly set the time to midnight now,
    // but since that's 00:00 it'll already be the value
    // in the date components per the standard Cocoa object
    // creation components, so...

    // get the midnight that last occurred
    NSDate *lastMidnight = [relevantCalendar dateFromComponents:componentsForNow];

    // can we just add 24 hours to that? No, because of DST. So...

    // create components that specify '1 day', however long that may be
    NSDateComponents *oneDay = [[NSDateComponents alloc] init];
    oneDay.day = 1;

    // hence ask the calendar what the next midnight will be
    NSDate *nextMidnight = [relevantCalendar
                 dateByAddingComponents:oneDay
                 toDate:lastMidnight
                 options:0];
    [oneDay release];

    // now create a timer to fire at the next midnight, to call
    // our periodic function. NB: there's no convenience factory
    // method that takes an NSDate, so we'll have to alloc/init
    NSTimer *timer = [[NSTimer alloc]
                 initWithFireDate:nextMidnight
                 interval:0.0 // we're not going to repeat, so...
                 target:self
                 selector:@selector(doTimedAction:)
                 userInfo:nil
                 repeats:NO];

    // schedule the timer on the current run loop
    [[NSRunLoop currentRunLoop]
                 addTimer:timer
                 forMode: NSDefaultRunLoopMode];

    // timer is retained by the run loop, so we can forget about it
    [timer release];
}

- (void)doTimedAction:(NSTimer *)timer
{
    NSLog(@"do action");
    [self scheduleNextTimedAction];
}
Run Code Online (Sandbox Code Playgroud)