Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.8k views
in Technique[技术] by (71.8m points)

objective c - Schedule multiple, daily events with NSTimer?

I have a schedule cache stored in an NSDictionary.

For the example below, I have a schedule time of January 13, 20120 2:00PM and January 13, 2012 2:05PM. How can I add both of these to a queue to fire on their own?

Build the Schedule Cache:

-(void) buildScheduleCache
{  
    NSCalendarDate *now = [NSCalendarDate calendarDate];

    NSFileManager *manager = [[NSFileManager defaultManager] autorelease];
    path = @"/var/mobile/Library/MobileProfiles/Custom Profiles";
    theProfiles = [manager directoryContentsAtPath:path];

    myPrimaryinfo = [[NSMutableArray arrayWithCapacity:6] retain];
    keys = [NSArray arrayWithObjects:@"Profile",@"MPSYear",@"MPSMonth",@"MPSDay",@"MPSHour",@"MPSMinute",nil];

    for (NSString *profile in theProfiles) 
    {
        plistDict = [[[NSMutableDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/%@",path,profile]] autorelease];

        [myPrimaryinfo addObject:[NSDictionary dictionaryWithObjects:
                                  [NSArray arrayWithObjects:
                                   [NSString stringWithFormat:@"%@",profile], 
                                   [NSString stringWithFormat:@"%@",[plistDict objectForKey:@"MPSYear"]], 
                                   [NSString stringWithFormat:@"%@",[plistDict objectForKey:@"MPSMonth"]], 
                                   [NSString stringWithFormat:@"%@",[plistDict objectForKey:@"MPSDay"]], 
                                   [NSString stringWithFormat:@"%@",[plistDict objectForKey:@"MPSHour"]], 
                                   [NSString stringWithFormat:@"%@",[plistDict objectForKey:@"MPSMinute"]],
                                   nil]forKeys:keys]];

        profileSched =
        [NSCalendarDate dateWithYear:[plistDict objectForKey:@"MPSYear"]
                               month:[plistDict objectForKey:@"MPSMonth"]
                                 day:[plistDict objectForKey:@"MPSDay"]
                                hour:[plistDict objectForKey:@"MPSHour"]
                              minute:[plistDict objectForKey:@"MPSMinute"]
                              second:01
                            timeZone:[now timeZone]];

        [self rescheduleTimer];
    }

    NSString *testPath = @"/var/mobile/Library/MobileProfiles/Schedules.plist";
    [myPrimaryinfo writeToFile:testPath atomically:YES];
}

Schedule The Event:

-(void) scheduleProfiles
{
    NSFileManager *manager = [[NSFileManager defaultManager] autorelease];
    path = @"/var/mobile/Library/WrightsCS/MobileProfiles/Custom Profiles";
    theProfiles = [manager contentsOfDirectoryAtPath:path error:nil];

    for (NSString *profile in theProfiles) 
    {
        NSMutableDictionary * plistDict = [[[NSMutableDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/%@",path,profile]] autorelease];

        profileSched =
        [NSCalendarDate dateWithYear:[[plistDict objectForKey:@"MPSYear"] intValue]
                               month:[[plistDict objectForKey:@"MPSMonth"] intValue]
                                 day:[[plistDict objectForKey:@"MPSDay"] intValue]
                                hour:[[plistDict objectForKey:@"MPSHour"] intValue]
                              minute:[[plistDict objectForKey:@"MPSMinute"] intValue]
                              second:01
                            timeZone:[NSTimeZone localTimeZone]];


            NSLog(@"DATE: %@      SCHEDULE: %@      PROFILE: %@",[NSDate date],profileSched,profile);
        if([NSDate date] < profileSched)
        {
            NSLog(@"IGNORING PROFILE: %@     WITH SCHEDULE: %@",profile,profileSched);
        }else{
            //Create the timer from the Cached Array
            schedTimer = [[NSTimer alloc] initWithFireDate:profileSched //[NSDate dateWithTimeIntervalSinceNow: 10]
                                                  interval:0.1f
                                                    target:self
                                                  selector:@selector(fireCustomProfile:)
                                                  userInfo:profile
                                                   repeats:NO];//[[plistDict objectForKey:@"MPSRepeat"] boolValue]];

            MLogString(@"Scheduling Profile: %@",profile);
            [[NSRunLoop currentRunLoop] addTimer:schedTimer forMode:NSDefaultRunLoopMode];
        }
    }
}

Fire the Event:

-(void)fireCustomProfile:(NSTimer *)timer
{   
    if([[NSDate date] earlierDate:[schedTimer fireDate]])
    {
        NSLog(@"Ignoring Profile: %@",[schedTimer userInfo]);
        return;
    }

    notify_post("com.wrightscs.MobileProfiles.setCustomProfile");
}

Example Event:

<array>
    <dict>
        <key>MPSDay</key>
        <string>13</string>
        <key>MPSHour</key>
        <string>21</string>
        <key>MPSMinute</key>
        <string>15</string>
        <key>MPSMonth</key>
        <string>1</string>
        <key>MPSYear</key>
        <string>2012</string>
        <key>Profile</key>
        <string>Event 1</string>
        <key>Repeat</key>
        <true/>
    </dict>
</array>
<array>
    <dict>
        <key>MPSDay</key>
        <string>13</string>
        <key>MPSHour</key>
        <string>21</string>
        <key>MPSMinute</key>
        <string>20</string>
        <key>MPSMonth</key>
        <string>1</string>
        <key>MPSYear</key>
        <string>2012</string>
        <key>Profile</key>
        <string>Event 2</string>
        <key>Repeat</key>
        <true/>
    </dict>
</array>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Are you sure a timer is what you want? Remember, a timer is only active when your app is active. It does not work when the app is inactive. If you're trying to get your app to do something at any time in the distant future, a timer will not really solve your problem because every time you quit the app, all its timers die.

Assuming that (1) you do just want to set timers for events while the app is active and (2) you always have an unknown number of events in the queue, then your biggest problem will be sorting out how to target an arbitrary number of timers for an arbitrary number of events.

Fortunately, timers can pass any arbitrary object in their userInfo property so you want to wrap every event in an object and pass that object to the timer. Then the timer fired method can extract the event and act on it.

Something like this:

// assume a data model with event objects with the attributes and methods shown

- (void) setTimerForEvent:(EventClass *) anEvent{
    [NSTimer timerWithTimeInterval:[anEvent eventTimeFromNow] 
                            target:self 
                          selector:@selector(fireEvent:) 
                          userInfo:anEvent 
                           repeats:NO];

}//------------------------------------setTimerForEvent:------------------------------------

- (void)fireEvent:(NSTimer*)theTimer{
    [self handleEvent:(EventClass *)theTimer.userInfo]; 
    [theTimer invalidate];
}//------------------------------------fireEvent:------------------------------------

The -[EventClass eventTimeFromNow] should return a NSTimerInterval of the seconds remaining between the time the method is called and time of the event.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...