Расписание нескольких ежедневных событий с NSTimer? - PullRequest
1 голос
/ 14 апреля 2010

У меня есть кэш расписания, хранящийся в NSDictionary.

Для приведенного ниже примера у меня есть расписание 13 января 20120 года 2:00 PM и 13 января 2012 года 2:05 PM Как я могу добавить их обоих в очередь, чтобы выстрелить самостоятельно?

Создание кэша расписания:

-(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];
}

Расписание мероприятия:

-(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];
        }
    }
}

Запустить событие:

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

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

Пример события:

<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>

Ответы [ 3 ]

4 голосов
/ 16 апреля 2010

Вы уверены, что таймер это то, что вы хотите? Помните, таймер активен только тогда, когда ваше приложение активно. Это не работает, когда приложение неактивно. Если вы пытаетесь заставить свое приложение что-то сделать в любое время в отдаленном будущем, таймер не решит вашу проблему, потому что каждый раз, когда вы выходите из приложения, все его таймеры умирают.

Предполагая, что (1) вы просто хотите установить таймеры для событий, пока приложение активно, и (2) у вас всегда есть неизвестное количество событий в очереди, тогда вашей самой большой проблемой будет выяснить, как нацелить произвольное количество таймеров для произвольного числа событий.

К счастью, таймеры могут передавать любой произвольный объект в свойстве userInfo, поэтому вы хотите обернуть каждое событие в объекте и передать этот объект таймеру. Затем метод, запущенный по таймеру, может извлечь событие и воздействовать на него.

Примерно так:

// 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:------------------------------------

-[EventClass eventTimeFromNow] должен возвращать NSTimerInterval секунд, оставшихся между временем вызова метода и временем события.

3 голосов
/ 19 января 2012

Вы можете использовать UILocalNotification вместо NSTimer. Ограничения заключаются в том, что в вашем приложении нет действий без вашего взаимодействия, но выдается уведомление, даже если приложение закрыто.

Документация Apple о UILocalNotifications :

Экземпляры UILocalNotification представляют собой уведомления о том, что Приложение может запланировать презентацию для своих пользователей на определенных даты и время Операционная система отвечает за доставку уведомление в нужное время; приложение не должно бежать, чтобы это произошло.

...

Когда система доставляет локальное уведомление, несколько вещей могут в зависимости от состояния приложения и типа уведомление. Если приложение не является передним и видимым, Система отображает предупреждающее сообщение, обозначает приложение и воспроизводит звук - все, что указано в уведомлении. Если уведомление является предупреждением, и пользователь нажимает кнопку действия (или, если устройство заблокирован, перетаскивает ползунок действия), приложение запускается. В приложение: didFinishLaunchingWithOptions: метод приложения делегат может получить объект UILocalNotification из переданного словарь опций с помощью UIApplicationLaunchOptionsLocalNotificationKey key. Делегат может проверить свойства уведомления и, если уведомление включает пользовательские данные в свой словарь userInfo, он может получить доступ к данные и обработать его соответственно. С другой стороны, если местный уведомление только значок приложения, а пользователь в ответ запускает приложение, application: didFinishLaunchingWithOptions: метод вызывается, но нет Объект UILocalNotification включен в словарь опций.

Если приложение является основным и видимым, когда система доставляет уведомление, предупреждение не отображается, значок не помечен значком и нет звука играет. Тем не менее, приложение: didReceiveLocalNotification: есть Вызывается, если его выполняет делегат приложения. Экземпляр UILocalNotification передается в этот метод, а Делегат может проверить свои свойства или получить доступ к любым пользовательским данным из словарь userInfo.

Вы можете найти хороший учебник здесь , где основная идея такова:

Настройка уведомлений:

Class cls = NSClassFromString(@"UILocalNotification");
if (cls != nil) {
    UILocalNotification *notif = [[cls alloc] init];
    notif.fireDate = [datePicker date];
    notif.timeZone = [NSTimeZone defaultTimeZone];

    notif.alertBody = TEXT;
    notif.alertAction = LAUNCH_BUTTON;
    notif.soundName = UILocalNotificationDefaultSoundName;
    notif.applicationIconBadgeNumber = NOTIFICATIONS_REMAINING;

    NSDictionary *userDict = [NSDictionary dictionaryWithObject:CUSTOM_INFO 
                                            forKey:kRemindMeNotificationDataKey];
    notif.userInfo = userDict;

    [[UIApplication sharedApplication] scheduleLocalNotification:notif];
    [notif release];
}

Обработка уведомления, когда приложение не запущено (в делегате приложения):

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

    Class cls = NSClassFromString(@"UILocalNotification");
    if (cls) {
        UILocalNotification *notification = [launchOptions objectForKey:
                        UIApplicationLaunchOptionsLocalNotificationKey];

        if (notification) {
            NSString *reminderText = [notification.userInfo 
                        objectForKey:kRemindMeNotificationDataKey];
           [viewController showReminder:reminderText];
        }
    }

    application.applicationIconBadgeNumber = NOTIFICATIONS_REMAINING_LESS_ONE;

    [window addSubview:viewController.view];
    [window makeKeyAndVisible];

    return YES;
}

Заявка на переднем плане (в делегате приложения):

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {

    UIApplicationState state = [application applicationState];
    if (state == UIApplicationStateInactive) {
        // Application was in the background when notification
        // was delivered.
    }
}
0 голосов
/ 14 апреля 2010

Вам понадобится таймер для каждого события. Возможно, не назначайте таймер переменной timer. Вы можете просто создать эти таймеры и выпустить их в theFireEvent. Вам нужно изменить этот селектор на @selector(theFireEvent) и убедиться, что метод имеет подпись:

- (void)timerFireMethod:(NSTimer*)theTimer

...