【问题标题】:Fetch events from EKEventStore and show in tableView in Swift iOS8从 EKEventStore 获取事件并在 Swift iOS8 中的 tableView 中显示
【发布时间】:2014-07-13 12:16:10
【问题描述】:

我正在尝试创建一个小型应用程序,它将获取所有事件并将它们显示在 tableView 中。

我的具体问题是:

  1. 我的fetchEvents() 方法是否正确实现?
  2. 我应该在哪里调用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.
    }
}
}

【问题讨论】:

    标签: ios swift tableview ios8 ekeventstore


    【解决方案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 ,从而捕获了一个引用,这可能导致“reference cycle”。在这种特殊情况下,我很确定这不会发生,因为 requestAccessToEntityType() 不会保留对您的闭包的引用(我非常确定),但使用它是一个好主意[weak self] 每当您在回调函数中使用 self 时:

    一旦你这样做了,self 是一个可选的,所以你需要确保它不是 nil…

    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 可能是假的,这意味着用户没有给你访问权限,或者可能有错误(所以你需要检查 @ 987654335@ 为零 (if error { /* handle failure */ })

    PS - 我有working code which uses event kit on github,您可能会觉得有用。

    【讨论】:

    • 非常感谢您详尽的回答!一件小事,我如何以及从哪里调用 fetchEvents() 方法?它在 viewDidLoad 中吗?我尝试调用 self.fetchEvents(objects),但是,我收到此错误:无法将表达式的类型“()”转换为类型“(NSMutableArray)-> Void”。谢谢!
    • @shila viewDidLoad 是一个调用它的好地方,问题是你需要传递一个回调:self.fetchEvents(completed: { (events: NSMutableArray) -> Void in })
    猜你喜欢
    • 1970-01-01
    • 2021-05-25
    • 2018-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多