Search code examples
iosarraysswiftuitablevieweventkit

Save Event to Calendar from API when Button in TableViewCell is Pressed


I would like to have the same "Save to Calendar Button" in every row of a tableView and each button opens a different Event from JSON imported through an api using decodable.

I need to assign the indexPath.row for each button so that the first button fills with the information from the first JSON object, the second button fills with the information from the second JSON object, ect... There's an example of the tableview below. I want each button to save a different event to a user's calendar with the "Title" passed from the api. (The same title that's passed to the "Title" UILabel you see below.) I would also like the "Description" to autofill with the description from the api. I have imported the json information using decodable.

enter image description here

Here is the cellForRowAt code found in the viewController:

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "eventCell", for: indexPath) as! EventTableViewCell
        let item = page!.tradeshows[indexPath.row]

        cell.registrationUrl = item.link
        cell.eventTitle.text = item.title
        cell.eventDate.text = item.tradeshowDescription
        cell.addEventToCalendar(title: item.title!, description: item.tradeshowDescription, startDate: NSDate() as Date, endDate: NSDate() as Date)


        return cell
    }

I need the JSON information that is applied above (title: item.title!) and (description: item.tradeshowDescription) to autofill the information when the "Save to Calendar" button is pressed in each row. I need the indexPath to be assigned so that the information that autofills the event when saved to calendar is the correct information for each row.

Any advice is appreciated.

Custom Xib Cell Class Code found in the TableViewCell:

import UIKit
import EventKit

class EventTableViewCell: UITableViewCell {

    var registrationUrl : URL!

    @IBOutlet weak var eventDate: UILabel!
    @IBOutlet weak var eventTitle: UILabel!
    @IBOutlet weak var saveToCalendarButton: UIButton!
    @IBOutlet weak var registerButton: UIButton!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code

        selectionStyle = UITableViewCell.SelectionStyle.none
    }


    @IBAction func registerButtonPressed(_ sender: Any) {

        UIApplication.shared.open(registrationUrl)
    }


    @IBAction func saveToCalenderButtonPressed(_ sender: Any) {

       addEventToCalendar(title: "", description: "", startDate: NSDate() as Date, endDate: NSDate() as Date)

    }

    func addEventToCalendar(title: String, description: String?, startDate: Date, endDate: Date, completion: ((_ success: Bool, _ error: NSError?) -> Void)? = nil) {

        let eventStore = EKEventStore()

        eventStore.requestAccess(to: .event, completion: { (granted, error) in
            if (granted) && (error == nil) {
                let event = EKEvent(eventStore: eventStore)
                event.title = title
                event.startDate = startDate
                event.endDate = endDate
                event.notes = description
                event.calendar = eventStore.defaultCalendarForNewEvents
                do {
                    try eventStore.save(event, span: .thisEvent)
                } catch let e as NSError {
                    completion?(false, e)
                    return
                }
                completion?(true, nil)
            } else {
                completion?(false, error as NSError?)
            }
        })
    }

}

Solution

  • rewrite the cellForRow method.

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let cell = tableView.dequeueReusableCell(withIdentifier: "eventCell", for: indexPath) as! EventTableViewCell
        let item = page!.tradeshows[indexPath.row]
    
        cell.registrationUrl = item.link
        cell.eventTitle.text = item.title
        cell.eventDate.text = item.tradeshowDescription
        cell.saveToCalendarButton.tag = indexPath.row
        cell.saveToCalendarButton.addTarget(self, action: #selector(saveToCalenderButtonPressed(sender:)), for: .touchUpInside)
    
    
        return cell
    }
    

    then in the viewController you have to write the following function.

    @IBAction func saveToCalenderButtonPressed(_ sender: Any) {
    
       guard let index = (sender as? UIButton).tag else {return}
       let item = eventArray[index]
       addEventToCalendar(title: item.title ?? "", description:item.tradeshowDescription, startDate: Date(), endDate: Date()){ (granted, error) in
    if error == nil{
      print("success")
    }else{
      print("error added to calendar")
        }
     }
    

    and add this other function to viewController.

    func addEventToCalendar(title: String, description: String?, startDate: Date, endDate: Date, completion: ((_ success: Bool, _ error: Error?) -> Void)? = nil) {
        let eventStore = EKEventStore()
        eventStore.requestAccess(to: .event, completion: { (granted, error) in
            if (granted) && (error == nil) {
                let event = EKEvent(eventStore: eventStore)
                event.title = title
                event.startDate = startDate
                event.endDate = endDate
                event.notes = description
                event.calendar = eventStore.defaultCalendarForNewEvents
                do {
                    try eventStore.save(event, span: .thisEvent)
                } catch{
                    completion?(false, error)
                    return
                }
                completion?(true, nil)
            } else {
                completion?(false, error?)
            }
        })
    }
    

    so you viewController is responsible to add to event to calendar. and when user touch button in the cell you have to get the index of the array, with the sender tag that is equal to the indexPath.row of the cell.