Извлекать события из EKEventStore и показывать в tableView в Swift iOS8
Я пытаюсь создать небольшое приложение, которое будет извлекать все события и отображать их в виде таблицы.
Мои конкретные вопросы:
- Мой
fetchEvents()
метод реализован правильно? - Где я должен позвонить
fetchEvent()
метод, чтобы показать список, когда приложение открывается (это вviewDidLoad
?) и обновить его после добавления / редактирования нового события?
Спасибо!
Это мой код для MasterViewController.swift
файл:
import UIKit
import EventKitUI
class MasterViewController: UITableViewController , EKEventEditViewDelegate{
var objects = NSMutableArray()
let eventStore = EKEventStore()
override func awakeFromNib() {
super.awakeFromNib()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.leftBarButtonItem = self.editButtonItem()
let addButton = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "insertNewObject:")
self.navigationItem.rightBarButtonItem = addButton
//self.fetchEvents()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func insertNewObject(sender: AnyObject) {
let controller = EKEventEditViewController()
eventStore.requestAccessToEntityType(EKEntityType(), completion: {granted, error in })
controller.eventStore = eventStore
controller.editViewDelegate = self
self.presentModalViewController(controller, animated: true)
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
func eventEditViewController(controller: EKEventEditViewController!, didCompleteWithAction action: EKEventEditViewAction) {
self.dismissModalViewControllerAnimated(true)
}
func fetchEvents() -> NSMutableArray {
eventStore.requestAccessToEntityType(EKEntityType(), completion: {granted, error in })
let endDate = NSDate(timeIntervalSinceNow: 604800*10); //This is 10 weeks in seconds
let predicate = self.eventStore.predicateForEventsWithStartDate(NSDate(), endDate: NSDate(), calendars: nil)
var events = NSMutableArray(array: self.eventStore.eventsMatchingPredicate(predicate))
return events
/*
var indexes = NSMutableIndexSet(index: 5)
indexes.addIndex(4)
objects.insertObjects(events, atIndexes: indexes) */
// Create the start date components
/* NSDateComponents *oneDayAgoComponents = [[NSDateComponents alloc] init];
oneDayAgoComponents.day = -1;
let oneDayAgo = currentCalendar.date dateByAddingComponents:oneDayAgoComponents*/
}
// #pragma mark - Segues
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
let indexPath = self.tableView.indexPathForSelectedRow()
let object = objects[indexPath.row] as NSDate
(segue.destinationViewController as DetailViewController).detailItem = object
}
}
// #pragma mark - Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
let object = objects[indexPath.row] as NSDate
cell.textLabel.text = object.description
return cell
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
objects.removeObjectAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
} else if editingStyle == .Insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
}
1 ответ
Прежде всего, вы должны делать остальную часть работы в вашем fetchEvents
функция внутри обратного вызова для eventStore.requestAccessToEntityType
:
func fetchEvents() -> NSMutableArray {
eventStore.requestAccessToEntityType(EKEntityType()) completion: {
granted, error in
... the rest of the code ...
})
}
конечно теперь, когда это асинхронно, вам нужно будет возвращать данные в обратном вызове, а не возвращать их:
func fetchEvents(completed: (NSMutableArray) -> ()) {
eventStore.requestAccessToEntityType(EKEntityType()) completion: {
granted, error in
let endDate = NSDate(timeIntervalSinceNow: 604800*10); //This is 10 weeks in seconds
let predicate = self.eventStore.predicateForEventsWithStartDate(NSDate(), endDate: NSDate(), calendars: nil)
let events = NSMutableArray(array: self.eventStore.eventsMatchingPredicate(predicate))
completed(events)
})
}
Но теперь у вас есть другая проблема... вы используете self в замыкании, тем самым захватывая ссылку, что может привести к " циклу ссылок ". В этом конкретном случае я уверен, что этого не произойдет, потому что requestAccessToEntityType()
не будет хранить ссылку на ваше закрытие (я уверен), но это хорошая идея для использования [weak self]
всякий раз, когда вы используете self
внутри функции обратного вызова:
как только вы это сделаете, self является необязательным, так что вам нужно убедиться, что это не ноль…
func fetchEvents(completed: (NSMutableArray) -> ()) {
eventStore.requestAccessToEntityType(EKEntityType()) completion: { [weak self]
granted, error in
if let strongSelf = self {
let endDate = NSDate(timeIntervalSinceNow: 604800*10); //This is 10 weeks in seconds
let predicate = strongSelf.eventStore.predicateForEventsWithStartDate(NSDate(), endDate: NSDate(), calendars: nil)
let events = NSMutableArray(array: strongSelf.eventStore.eventsMatchingPredicate(predicate))
completed(events)
}
})
}
но, присмотревшись немного ближе, мы никогда не используем self
просто self.eventStore
так что вместо этого мы можем зафиксировать слабую ссылку на это:
func fetchEvents(completed: (NSMutableArray) -> ()) {
eventStore.requestAccessToEntityType(EKEntityType()) completion: { [weak weakEventStore = self.eventStore]
granted, error in
if let eventStore = weakEventStore {
let endDate = NSDate(timeIntervalSinceNow: 604800*10); //This is 10 weeks in seconds
let predicate = eventStore.predicateForEventsWithStartDate(NSDate(), endDate: NSDate(), calendars: nil)
let events = NSMutableArray(array: eventStore.eventsMatchingPredicate(predicate))
completed(events)
}
})
}
наконец, вы действительно должны проверять ошибки, а не игнорировать их, (granted
может быть ложным, что означает, что пользователь не предоставил вам доступ, или могла произойти ошибка (поэтому необходимо проверить, error
ноль (if error { /* handle failure */ }
)
PS - у меня есть рабочий код, который использует набор событий на GitHub, который вы можете найти полезным.