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

时间:2012-01-28 14:21:43

标签: iphone objective-c multithreading timer while-loop

我有以下(terible)方法不断检查当前时间,并且当达到特定时间(在这种情况下是午夜)时,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];

}

}

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

[self performSelectorInBackground:@selector(checkTime) withObject:nil];

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

谢谢,

杰克

3 个答案:

答案 0 :(得分:5)

你会好起来的:

  1. 获取当前日期;
  2. 今天午夜时分锻炼身体;
  3. 在一天之后安排一次性定时器;和
  4. 重复
  5. 很容易安排一个重复计时器,该计时器首先使用(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];
    }
    

答案 1 :(得分:3)

如果您想在任意时间点执行代码,最好设置本地通知。

答案 2 :(得分:0)

如果计时器还应在您的应用未运行Push notification guideNSTimer时提醒用户,则可以使用UILocalNotification,也可以使用触发日期或间隔进行初始化作为要调用的选择器。请注意,如果您的应用在后台,NSTimer将无法触发,但在这种情况下,相反会在您的应用再次激活时触发。