【问题标题】:Value of type 'Any?' has no member 'tag'“任何?”类型的值没有成员“标签”
【发布时间】:2018-01-11 11:56:02
【问题描述】:

我在我的自定义 tableViewCell 上添加了一个按钮,我希望在点击按钮后,它会根据按钮所在的单元格传递数据,因此要找出哪个单元格是按钮,我添加了一个标签,但是我收到了这个错误

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "goToLast" && sender is IndexPath {


             let dvc = segue.destination as! FinalClass 
            dvc.index = (sender as! IndexPath).row
            dvc.places = sortedArray
            dvc.userLocation = currentLocation

            }
        if segue.identifier == "goToReview" {

            let index3 = IndexPath(row: sender.tag, section: 0)
            let rev = segue.destination as! ReviewClass


        }

}

如何调整?

(cell.reviewButton.tag = indexPath.row) 这是我在 cellForRowAt 中添加的标签

更新

这是我的 VC 中的按钮操作

  @IBAction func ReviewButtonTap(_ sender: UIButton) {

      performSegue(withIdentifier: "goToReview" , sender: self)
    }

这是我的自定义 tableViewCell 类中的插座

 @IBOutlet weak var reviewButton: UIButton!

我不明白如何将此按钮与

else if segue.identifier == "goToReview", let button = sender as? UIButton, let rev = segue.destination as? ReviewClass {
            let index3 = IndexPath(row: button.tag, section: 0)

【问题讨论】:

  • 将sender转换为按钮first,然后获取按钮标签。
  • 即使您可以在用户点击按钮时全局存储选定的索引,而不是在 segue 中获取索引。这是编写代码的正确方法。
  • 你需要转换成 UIButton 然后你应该可以使用 .tag

标签: ios swift uitableview swift4


【解决方案1】:

强制将可选的Any 向下转换为预期的UIButtonIndexPath,并使用else 子句而不是if 两次

 if segue.identifier == "goToLast" {
        let dvc = segue.destination as! FinalClass 
        let indexPath = sender as! IndexPath
        dvc.index = indexPath.row
        dvc.places = sortedArray
        dvc.userLocation = currentLocation
}
else if segue.identifier == "goToReview" {
        let button = sender as! UIButton
        let index3 = IndexPath(row: button.tag, section: 0)
        let rev = segue.destination as! ReviewClass
}

或使用switch

 switch segue.identifier {
     case "goToLast":
        let dvc = segue.destination as! FinalClass 
        let indexPath = sender as! IndexPath
        dvc.index = indexPath.row
        dvc.places = sortedArray
        dvc.userLocation = currentLocation

    case "goToReview":
        let button = sender as! UIButton
        let index3 = IndexPath(row: button.tag, section: 0)
        let rev = segue.destination as! ReviewClass

    default: break
}

代码不得崩溃。如果是这样,你就犯了设计错误。

编辑

您必须将UIButton 实例(sender)从IBAction 传递到performSeguesender 参数。出口无关紧要。

performSegue(withIdentifier: "goToReview" , sender: sender)

【讨论】:

  • 好的,但有一个问题,@IBAction func ReviewButtonTap(_ sender: UIButton) { performSegue(withIdentifier: "goToReview" , sender: self) } 这是我的按钮,我还需要定义一个出口吗?编译器如何将 let 按钮关联到这个函数?
  • 我假设您在某个地方调用 performSegue 并传递标识符和按钮。
【解决方案2】:

如果它可以是不同的对象,您通常会在您的方法中提供一个发件人Any。在这种情况下,您需要将其类型转换为特定对象,最好在 swift 中使用let button = sender as? UIButton

这样做您将收到一个可选值,其标记为button?.tag,其类型为Int?,然后再次禁止您创建索引路径。

所以这个方法的正确方法应该如下:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "goToLast", let indexPath = sender as? IndexPath {
            let dvc = segue.destination as! FinalClass 
            dvc.index = indexPath.row
            dvc.places = sortedArray
            dvc.userLocation = currentLocation
    } else if segue.identifier == "goToReview", let button = sender as? UIButton {
            let index3 = IndexPath(row: button.tag, section: 0)
            let rev = segue.destination as! ReviewClass
    }
}

请注意,我已经更改了两个 if 语句,甚至设法删除了一个额外的强制展开(! 的东西)。如果您不介意强制解包会在不正确时使您的应用程序崩溃,那么您也可以这样做:

let index3 = IndexPath(row: (sender as! UIButton).tag, section: 0) 

但我建议您避免所有强制展开以提高稳定性。对于您的情况:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "goToLast", let indexPath = sender as? IndexPath, let dvc = segue.destination as? FinalClass  {
            dvc.index = indexPath.row
            dvc.places = sortedArray
            dvc.userLocation = currentLocation
    } else if segue.identifier == "goToReview", let button = sender as? UIButton, let rev = segue.destination as? ReviewClass {
            let index3 = IndexPath(row: button.tag, section: 0)
    } else {
         print("ERROR: Incorrect configuration!") // Put a breakpoint here and analyze what was the identifier and what the sender so none of the statements were hit
    }
}

【讨论】:

  • 在这种情况下,强制展开非常好(甚至推荐)。如果崩溃,它将显示一个设计错误。如果一切都在 Interface Builder 中正确连接,则代码不得崩溃。在最坏的情况下使用您的第一个语法,代码什么都不做(不执行转场),您不知道为什么。
  • Matic 我更新了问题,因为我什么都不懂
  • @vadian 完全同意这种情况,这就是为什么我发布了两个版本,并且在非崩溃版本上添加了错误的打印,这样你就知道这是发生了什么。但我不同意这通常是你应该做的。某些配置可能未安装插座,或者它已被弃用,应检查。您可以相信我的话,在持续开发中您最好避免强制展开。
  • @fisherM 您问题的编辑部分似乎与原始问题无关。由于 vadian 已经更新,您需要将按钮而不是“self”发送到调用中以执行 performSegue。至于“不理解某件事”,您最好看看一些教程或一些涵盖 iOS 应用程序开发原始基础的东西。
【解决方案3】:

只是你需要用下面的方法改变你的segue方法

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "goToLast" && sender is IndexPath {


         let dvc = segue.destination as! FinalClass 
        dvc.index = (sender as! IndexPath).row
        dvc.places = sortedArray
        dvc.userLocation = currentLocation

        }
    if segue.identifier == "goToReview" {

        let index3 = IndexPath(row: (sender as! UIButton).tag, section: 0)
        let rev = segue.destination as! ReviewClass


    }
}

【讨论】:

    【解决方案4】:

    为了首先解决这个问题,你需要先在单元格中为你已经完成的行分配按钮标签。

    cell.reviewButton.tag = indexPath.row
    

    之后,您可以在行的单元格中的按钮上添加目标操作

    cell.reviewButton.addTarget(self, action:#selector(self. 
    func_Navigate(_:)), for:UIControlEvents.touchUpInside)
    

    行的外侧单元格实现一个这样的功能:-

    @IBAction func func_Navigate(_ sender: UIButton)
    {
    
    If sender.tag == 0
    
     {
    
        \\ here sender.tag = 0 means button belong from fist row of your table view. you can perform navigation like that :-
        self.performSegue(withIdentifier: "goToLast", sender: self)
    
    }
    else If sender.tag == 1
    
    {
        \\ here sender.tag = 1 means button belong from second row of your table view. you can perform navigation like that :-
        self.performSegue(withIdentifier: "goToReview", sender: self)
    }
    

    【讨论】:

    • 好的,所以在 func Navigation 的操作中,我将添加 performSegue(withIdentifier: "goToReview" , sender: sender) 对吗?在我的函数准备中,我怎么知道按钮被按下了哪一行?
    【解决方案5】:

    您可以从发送者那里获取 UIButton 对象,然后 UIButton 对象有标签属性可以访问。

    let button = sender as? UIButton
    let index3 = IndexPath(row: button?.tag ?? 0, section: 0)
    

    【讨论】:

    • 索引路径中不能有可选整数。所以也许IndexPath(row: button?.tag ?? 0, section: 0) 默认为0。但这没有意义,这是一个需要处理的异常。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-28
    • 2017-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多