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.
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?)
}
})
}
}
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.