下面我们讨论如何在iOS中创建日历事件。日历事件主要涉及到EventKit框架。
首先我们需要对工程添加框架。点击工程查看属性,在Linked FrameWorks and Libraries中增加EventKit框架,并且将EventKit通过鼠标拖动移动到Frameworks文件夹:
下面我们去创建一个按钮事件。
- (IBAction)addEvent:(id)sender {
// create a new Event
EKEvent *event = [EKEvent eventWithEventStore: store];
// create start date & end date
NSDate *startDate = [[NSDate alloc] init];
NSDate *endDate = [[NSDate alloc] init];
// set event's properties
[event setTitle: @"an insert title"];
[event setStartDate: startDate];
[event setEndDate: endDate];
[event setAllDay: YES];
// insert new event into the default calendar
EKCalendar *calendar = [store defaultCalendarForNewEvents];
[event setCalendar: calendar];
// create an NSError pointer
NSError *err = nil;
// save event
[store saveEvent:event span:EKSpanThisEvent error:&err];
if (err == nil) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Congratulations" message:@"event create success." delegate:nil cancelButtonTitle:@"ok" otherButtonTitles:nil];
[alert show];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Failed" message:@"event create failed." delegate:nil cancelButtonTitle:@"ok" otherButtonTitles:nil];
[alert show];
}
}
在iOS 6以上版本中,我们需要对访问权限进行授权,所以我们需要做以下操作。头文件中:
#import <UIKit/UIKit.h>
#import <EventKit/EventKit.h>
@interface ViewController : UIViewController
- (IBAction)addEvent:(id)sender;
@property EKEventStore *store;
@property (strong, nonatomic) IBOutlet UIButton *myTestButton;
@end
.m文件:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
@synthesize store;
@synthesize myTestButton;
- (void)viewDidLoad
{
[super viewDidLoad];
// get Event Store
store = [[EKEventStore alloc] init];
[self requestCalendarAccess];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// This method is called when the user has granted permission to Calendar
-(void)accessGrantedForCalendar
{
// Update the UI with the above events
[myTestButton setEnabled:YES];
}
// Prompt the user for access to their Calendar
-(void)requestCalendarAccess
{
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error)
{
if (granted)
{
// Let's ensure that our code will be executed from the main queue
dispatch_async(dispatch_get_main_queue(), ^{
[self accessGrantedForCalendar];
});
}
}];
}
@end
以上是个简单的例子,下面我们看一个更复杂的代码。
建立项目
- 我们建立一个Master-Detail类型的工程,使用Storyboard。
- 这次我们添加两个Framework,分别是EventKit和EventKitUI。
- 第一个页面使用TableViewController,用于展现事件列表。
- 第二个页面使用ViewController,用于展现事件描述;
- 注意在AppDelegate.m中添加:
@synthesize window;
//
// MasterViewController.m
// EventManager
//
// Created by Sam Wang on 13-7-24.
// Copyright (c) 2013年 cn.impressmedia. All rights reserved.
//
#import "MasterViewController.h"
#import "DetailViewController.h"
@interface MasterViewController () {
// NSMutableArray *_objects;
}
@end
@implementation MasterViewController;
@synthesize store;
@synthesize eventArray;
@synthesize canDealWithEvent;
- (void)awakeFromNib
{
[super awakeFromNib];
}
// 请求获取日历应用的部分权限
-(void)requestCalendarAccess {
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted) {
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"gain event access");
self.canDealWithEvent = YES;
});
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"we haven't got any event access, so we can do nothing except exit.");
self.canDealWithEvent = NO;
});
}
}];
}
// 刷新事件数组
-(void)refreshEventArray {
if (canDealWithEvent == YES) {
return ;
}
// 从现在开始
NSDate *startDate = [NSDate date];
// 从现在开始的一个月时间
NSDateComponents *tomorrowDateComponents = [[NSDateComponents alloc] init];
// day year,等等均可设置
tomorrowDateComponents.month = 1;
NSDate *endDate = [[NSCalendar currentCalendar] dateByAddingComponents:tomorrowDateComponents
toDate:startDate
options:0];
// 仅搜索默认日历对象
NSArray *calendarArray = [NSArray arrayWithObject:self.store.defaultCalendarForNewEvents];
NSPredicate *predicate = [self.store predicateForEventsWithStartDate:startDate
endDate:endDate
calendars:calendarArray];
// 搜索满足断言的事件
eventArray = [NSMutableArray arrayWithArray:[self.store eventsMatchingPredicate:predicate]];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
canDealWithEvent = NO;
store = [[EKEventStore alloc] init];
[self requestCalendarAccess];
[self refreshEventArray];
self.navigationItem.leftBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)];
self.navigationItem.rightBarButtonItem = addButton;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)insertNewObject:(id)sender
{
if (!eventArray) {
eventArray = [[NSMutableArray alloc] init];
}
// create a new Event
EKEvent *event = [EKEvent eventWithEventStore: store];
// create start date & end date
NSDate *startDate = [[NSDate alloc] init];
NSDate *endDate = [[NSDate alloc] init];
// set event's properties
[event setTitle: @"new event"];
[event setStartDate: startDate];
[event setEndDate: endDate];
[event setAllDay: YES];
// insert new event into the default calendar
EKCalendar *calendar = [store defaultCalendarForNewEvents];
[event setCalendar: calendar];
// create an NSError pointer
NSError *err = nil;
// save event
[store saveEvent:event span:EKSpanThisEvent error:&err];
if (err == nil) {
NSLog(@"insert event success.");
[eventArray insertObject:[NSDate date] atIndex:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(eventArray.count - 1) inSection:0];
[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else {
NSLog(@"insert failed.");
}
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [eventArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
// NSDate *object = eventArray[indexPath.row];
// cell.textLabel.text = [object description];
EKEvent *event = eventArray[indexPath.row];
cell.textLabel.text = [event title];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[eventArray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDate *object = eventArray[indexPath.row];
[[segue destinationViewController] setDetailItem:object];
}
}
@end
apple的示例代码参见:SimpleEKDemo。