【发布时间】: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 单元格似乎无法识别里面的标签。
我猜当我注册单元格时,我还需要以某种方式让它知道里面的标签,但还没有找到怎么做。
应该显示所有细节的最终 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 时崩溃的错误无关。
我添加了更多图片,以便更好地了解究竟发生了什么以及应用内导航的工作原理。
在这里您可以看到主故事板和一些转场。
当按下 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 将其拉开
这里是打开了 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 您有一个名为
handle的imageView,但我在您的故事板中看不到它。您是否删除了imageView并忘记了名称?