按下 TableViewCell 中的按钮时,将事件从 API 保存到日历

Posted

技术标签:

【中文标题】按下 TableViewCell 中的按钮时,将事件从 API 保存到日历【英文标题】:Save Event to Calendar from API when Button in TableViewCell is Pressed 【发布时间】:2019-11-18 17:57:35 【问题描述】:

我希望在 tableView 的每一行中都有相同的“保存到日历按钮”,并且每个按钮从通过 api 使用可解码的 JSON 导入的 JSON 中打开一个不同的事件。

我需要为每个按钮分配 indexPath.row 以便第一个按钮填充来自第一个 JSON 对象的信息,第二个按钮填充来自第二个 JSON 对象的信息,等等...有一个示例下面的表格视图。我希望每个按钮使用从 api 传递的“标题”将不同的事件保存到用户的日历中。 (传递给您在下面看到的“标题”UILabel 的相同标题。)我还希望“描述”自动填充来自 api 的描述。我已经使用 decodedable 导入了 json 信息。

这是在 viewController 中找到的 cellForRowAt 代码:

        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
    

我需要上面应用的 JSON 信息(标题:item.title!)和(描述:item.tradeshowDescription),以便在每行中按下“保存到日历”按钮时自动填充信息。我需要分配 indexPath,以便在保存到日历时自动填充事件的信息是每一行的正确信息。

感谢任何建议。

在 TableViewCell 中找到自定义 Xib 单元类代码:

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


【问题讨论】:

你为什么要用 [String()] 而不是 [String]() 来创建一个 String() 类型的函数数组, 我不确定应该如何格式化该变量。我在每一行都有一个“保存事件”按钮。我希望当您单击第一行中的“保存事件”按钮时,它将带有标题的事件作为“标题”字符串从第一个 json 对象中的标题保存到用户的日历中。然后,如果您单击第二行中的下一个“保存事件”按钮,它会将第二个 json 对象的标题保存为事件标题。 正如我的评论中所建议的那样,您需要一个字符串数组,即 [String]() 以便您摆脱错误并能够将字符串保存在数组中 请添加addEventTocalendar的代码,这里是从保存到日历中读取的事件值。 当我使用“[String]()”时,此解决方案给我错误“无法将类型 '()' 的值分配给类型 '[String]”我添加了“addEventToCalender”代码。 【参考方案1】:

重写 cellForRow 方法。

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

然后在 viewController 中你必须编写以下函数。

@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")
    
 

并将这个其他功能添加到 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?)
        
    )

因此您的 viewController 负责将事件添加到日历中。 当用户触摸单元格中的按钮时,您必须获取数组的索引,发送者标记等于单元格的 indexPath.row。

【讨论】:

我无法让 IBAction 函数连接到我的 viewController,因为 IBOulet 在 EventTableViewCell.swift 文件中,如上所示。如果我从该文件中删除它,那么当我尝试在 cellforRowAt 中引用它时,它找不到出口,因为它正在“eventCell”中查找 我说你必须从单元格中删除并将其添加到视图控制器,这样你就可以将目标连接到按钮而不执行操作。因此单元格中的按钮没有@IBAction,您可以在 addTarget 函数中为其添加目标。

以上是关于按下 TableViewCell 中的按钮时,将事件从 API 保存到日历的主要内容,如果未能解决你的问题,请参考以下文章

如何更改特定 TableViewCell 中的按钮颜色

按钮目标不执行 TableViewCell 中的功能

tableviewcell 内的 UIButton 触发单元格而不是按钮 [重复]

为 TableViewCell 创建 UI 按钮

在 TableViewCell 内单击时 UIButton 标签重置

UITableViewCell 中的按钮 [重复]