【问题标题】:App crashes when navigating to tableView from a xib从 xib 导航到 tableView 时应用程序崩溃
【发布时间】:2019-09-17 11:28:57
【问题描述】:

我正在努力寻找答案,并想我会尝试在这里提问。

我有一个在 navigationController 中使用 UITableView 控制器的应用。 tableView 有 2 个带有自定义类的单元格,这些单元格本身是在 storyBoard 中创建的。 这些单元格只有一个标签和一些小的视觉调整。

此外,主页上还有一种抽屉式的可扩展tableView,它被创建为一个xib文件。两者 - 当一个单元格被按下时,主 tableView 和 xib 会导致最后一个屏幕,并使用单元格中显示的地址在最终 tableView 中显示更详细的信息。

当我从 UITableViewController 导航到最终的 UITableView 时,一切正常,所有信息都很好地显示在单元格内,以及单元格内的标签。

现在,当我尝试从 xib 导航到同一个最终 tableViewController 时出现问题。 起初,应用程序崩溃了,我收到一条错误消息,提示我需要为标识符注册一个 nib 或一个类,或者在情节提要中连接一个原型单元。 当我尝试注册 nib 时,我会收到以下错误 Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key键句柄的值编码兼容。' 看起来我为 nibName 输入了错误的键,但我不确定除了 xib 文件的名称之外还可以输入什么。

编辑: 谢谢大家,手柄的错误是我现在修复的一个完全独立的小混淆,但主要问题仍然存在。 我在帖子底部添加了更多解释和信息。

我还尝试使用tableView.register(<cellClass: AnyClass?>, forCellReuseIdentifier: <String>) 注册单元格 这解决了应用程序崩溃的问题,但现在 tableView 单元格似乎无法识别里面的标签。

我猜当我注册单元格时,我还需要以某种方式让它知道里面的标签,但还没有找到怎么做。

Without registering the cell

With cell registered

应该显示所有细节的最终 tableViewController,包括带有标签的 detailLabel

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
      if indexPath.row == 0 {

         let cell = tableView.dequeueReusableCell(withIdentifier: "detailCell", for: indexPath)
         cell.textLabel?.text = "\(walletData.rowTitles[indexPath.section])"

         if let detailLabel = cell.viewWithTag(125) as? UILabel {

            switch indexPath.section {
            case 0:
               detailLabel.text = walletData.address
            case 1:
               detailLabel.text = "\(walletData.totalMNs)"
            case 2:
               detailLabel.text = walletData.totalShares
            case 3:
               detailLabel.text = "\(walletData.tiers[0].masterNodes.count)"
            case 4:
               detailLabel.text = "\(walletData.tiers[1].masterNodes.count)"
            case 5:
               detailLabel.text = "\(walletData.tiers[2].masterNodes.count)"
            case 6:
               detailLabel.text = "\(walletData.tiers[3].masterNodes.count)"
            default:
               detailLabel.text = "Sumtin' done messed up!"
            }
         }
         return cell
      } else {
         let cell = tableView.dequeueReusableCell(withIdentifier: "mnCell", for: indexPath)
         if let addressLabel = cell.viewWithTag(125) as? UILabel {
            let masterNode = walletData.tiers[indexPath.section - 3].masterNodes[indexPath.row - 1]
            addressLabel.text = masterNode.address
            switch masterNode.state {
            case 1:
               addressLabel.textColor = #colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1) // Initialize
            case 2:
               addressLabel.textColor = #colorLiteral(red: 0.9529411793, green: 0.6862745285, blue: 0.1333333403, alpha: 1) // Deposited
            case 3:
               addressLabel.textColor = #colorLiteral(red: 0.2745098174, green: 0.4862745106, blue: 0.1411764771, alpha: 1) // Active
            case 4:
               addressLabel.textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) // Terminate
            default:
               addressLabel.textColor = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1) // Unknown
            }
         }

         cell.textLabel?.text = walletData.tiers[indexPath.section - 3].masterNodes[indexPath.row - 1].shares
         cell.textLabel?.alpha = 0.75
         cell.backgroundColor = #colorLiteral(red: 0.921431005, green: 0.9214526415, blue: 0.9214410186, alpha: 1)
         cell.textLabel?.font = UIFont(name: "Helvetica Neue", size: 14)

         return cell
      }
   }

编辑:

感谢大家的回答。当我测试不同的选项时,我有点打嗝,忘记了代码中有 handle 插座,因此我没有识别出错误。但无论如何,这与我的应用从 xib 导航到最终 UITableView 时崩溃的错误无关。

我添加了更多图片,以便更好地了解究竟发生了什么以及应用内导航的工作原理。

在这里您可以看到主故事板和一些转场。

Storyboard

当按下 Address List Table View Controller 上的信息指示器时,这段代码会运行,用户会被带到 Detail Table View Controller,您可以看到在右下角。

override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
      if let selectedWallet = groupedWallets[indexPath.section].wallets[indexPath.row].address {
         walletData?.fetchWalletData(address: selectedWallet)

         DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
            if let detailTableViewController = self.storyboard?.instantiateViewController(withIdentifier: "detailTableViewController") as? DetailTableViewController {
               detailTableViewController.walletData = self.walletData!
               self.show(detailTableViewController, sender: self)
               SVProgressHUD.dismiss()
            }
         }
      }
   }

在这里你现在可以看到 xib 文件,它本质上只是一个带有小句柄的 UITableView 将其拉开

UITableView xib

这里是打开了 xib UITableView 的应用主页。

UITableView xib in running app

在这里您将看到 SavedListViewController 的代码,它是 xib 文件的所有者。

class SavedListViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

   let defaults = UserDefaults.standard
   let addressListVC = AddressListTableViewController()
   var selectedWallet = ""
   var savedWallets = [String]()
   var walletData = WalletData()
   let detailTableViewController = DetailTableViewController()

   @IBOutlet var handleArea: UIView!
   @IBOutlet var handle: UIImageView!
   @IBOutlet var tableView: UITableView!


   override func viewDidLoad() {
      guard let walletList = defaults.object(forKey: "savedWallets") as? [String] else { return }
      savedWallets = walletList

      //tableView.register(UINib.init(nibName: "SavedListView", bundle: nil), forCellReuseIdentifier: "detailCell")
      //tableView.register(UINib.init(nibName: "SavedListView", bundle: nil), forCellReuseIdentifier: "mnCell")

      view.layer.cornerRadius = 12
      handle.layer.cornerRadius = 6
      handleArea.backgroundColor = #colorLiteral(red: 0.921431005, green: 0.9214526415, blue: 0.9214410186, alpha: 1)
      handleArea.alpha = 0.90
      handle.alpha = 0.90
      view.backgroundColor = .clear
   }


   func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return savedWallets.count
   }

   func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
      tableView.register(UITableViewCell.self, forCellReuseIdentifier: "defaultCell")
      let cell = tableView.dequeueReusableCell(withIdentifier: "defaultCell", for: indexPath)
      if savedWallets.isEmpty {
         cell.textLabel?.text = "No addresses saved yet"
      } else {
         cell.textLabel?.text = savedWallets[indexPath.row]
      }
      return cell
   }


   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
      selectedWallet = savedWallets[indexPath.row]
      walletData.fetchWalletData(address: selectedWallet)
      detailTableViewController.walletData = walletData
      DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
         self.show(self.detailTableViewController, sender: self)
         SVProgressHUD.dismiss()
      }
   }  
}

所以,只是为了澄清在 xib 文件中创建的 UITableView 显示得很好。这是我打开应用程序时看到的第一件事,一切都在正确的位置并且可以正常工作。 当我点击单元格并调用 didSelectRowAt 方法时会发生崩溃。 方法本身是这样的

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
      selectedWallet = savedWallets[indexPath.row]
      walletData.fetchWalletData(address: selectedWallet)
      detailTableViewController.walletData = walletData
      DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
         self.show(self.detailTableViewController, sender: self)
         SVProgressHUD.dismiss()
      }
   }

该方法现在显示 detailTableViewController,它又是故事板图像的右下角。 该视图显示出来,但一旦let cell = tableView.dequeueReusableCell(withIdentifier: "detailCell", for: indexPath) 行被调用,它就会崩溃。 真正让我困惑的是,当我通过点击 *Address List Table View Controller** 中的行访问同一个 VC 时,一切正常。 但是当我点击 SavedListViewController 中的行时,我会收到错误 Terminating app due to uncaught exception 'NSInternalInconsistencyException',原因:'unable to dequeue a cell with identifier detailCell - must register a nib或标识符的类或连接故事板中的原型单元'

【问题讨论】:

  • 您是否为单元格创建了单独的 XIB 文件?通常可以做的是将 tableview 控制器嵌入到导航控制器中,然后在视图中创建原型单元格。如果你不这样做,那么你应该定义一个扩展 UITableViewCell 的类,然后将它与故事板连接
  • 欢迎新用户 - 顺便说一句,将图像放在问题中是完全可以的。 (编辑并直接将它们拖入)
  • 你能分享你的 xib 类吗?也尝试重新连接句柄引用。
  • 感谢 Fattie,显然我还没有使用这个特权。看起来我至少需要 10 个声望点才能直接添加图像。 @NickStefanidis,我将整个 xib 类添加到上面的帖子中。并用“手柄”插座清理了混乱。
  • @Henc 您有一个名为handleimageView,但我在您的故事板中看不到它。您是否删除了imageView 并忘记了名称?

标签: ios swift tableview xib


【解决方案1】:

你有没有可能把插座连接错了?当在带有 UITableViewCell 的 xib 中时,您必须从类的名称而不是文件的所有者连接插座:

  1. 保持文件所有者的渠道畅通:

  1. 将插座连接到班级:

【讨论】:

    【解决方案2】:

    检查您的视图控制器的插座是否连接正确。我猜在您当前的 VC 或您创建的单元格中有一个名为“handle”的插座,但它没有正确链接,或者您可能从主视图中删除了您的视图故事板,但它的出口在视图控制器中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-05
      • 2015-04-17
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多