使用NSTimer安排多个日常事件?
我有一个计划caching存储在一个NSDictionary
。
对于以下示例,我有一个计划时间为20120年1月13日下午2:00和2012年1月13日下午2:05 。 我怎样才能将这两个添加到队列来自己开火?
构build计划caching:
-(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>
您可以使用UILocalNotification而不是NSTimer。 限制是没有你的交互在你的应用程序中没有任何操作,但即使应用程序被closures,也会触发通知。
有关UILocalNotifications的 Apple文档:
UILocalNotification的实例表示应用程序可以安排在特定date和时间向用户呈现的通知。 操作系统负责在适当的时候发送通知; 应用程序不必运行这个事情。
…
当系统提供本地通知时,根据应用程序状态和通知types,可能会发生几件事情。 如果应用程序不是最前面和可见的,则系统将显示警报消息,标记应用程序并播放声音 – 无论通知中是否指定。 如果通知是警报,用户点击操作button(或者,如果设备被locking,则拖动打开操作滑块),则启动应用程序。 在应用程序中:didFinishLaunchingWithOptions:方法应用程序委托可以通过使用UIApplicationLaunchOptionsLocalNotificationKey键从传入的选项字典中获取UILocalNotification对象。 委托可以检查通知的属性,如果通知在其userInfo字典中包含自定义数据,则可以访问该数据并相应地处理该数据。 另一方面,如果本地通知仅标记应用程序图标,并且用户作为响应启动应用程序,则会调用application:didFinishLaunchingWithOptions:方法,但在选项字典中不包含UILocalNotification对象。
如果应用程序是最重要的,并且在系统发送通知时可见,则不显示警报,不显示图标,也不播放声音。 但是,应用程序:didReceiveLocalNotification:如果应用程序委托实现它,则会被调用。 UILocalNotification实例被传递给这个方法,委托可以检查它的属性,或者访问userInfo字典中的任何自定义数据。
你可以在这里find一个很好的教程,主要想法是这样的:
通知设置:
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]; }
在应用程序未运行时(在应用程序委托中)处理nofitication:
- (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. } }
你确定计时器是你想要的吗? 请记住,一个计时器只有在你的应用程序处 当应用程序处于非活动状态时,它不起作用。 如果你想让应用程序在遥远的将来随时做一些事情,一个计时器并不能真正解决你的问题,因为每次你退出应用程序,所有的计时器都会死掉。
假设(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]
应该返callback用方法的时间和事件的时间之间剩余秒数的NSTimerInterval。
你将需要一个计时器为每个事件。 也许不要把计时器分配给timer
variables。 您可以创build这些定时器并将其释放到theFireEvent
。 您需要将select器更改为@selector(theFireEvent)
,并确保该方法具有签名:
- (void)timerFireMethod:(NSTimer*)theTimer