通过Xib类触发searchSegue时提示无此标识符的问题求助
解决从Xib单元格触发Segue时的"Has no segue with identifier"错误
这个问题我之前也踩过坑,核心原因特别明确——Segue是ViewController之间的跳转连接,你的SearchCategoryRowCell作为一个UIView子类(单元格),本身根本没有绑定任何Segue,所以直接在cell里调用performSegue肯定会找不到对应的标识符。下面给你几个靠谱的解决思路,优先推荐前两种:
方法一:用代理(Delegate)让父ViewController触发Segue
这是最规范的解耦做法,能让cell和ViewController各司其职:
- 先在
SearchCategoryRowCell里定义代理协议:
protocol SearchCategoryRowCellDelegate: AnyObject { func searchCategoryCellDidTap(_ cell: SearchCategoryRowCell) } class SearchCategoryRowCell: UICollectionViewCell { weak var delegate: SearchCategoryRowCellDelegate? // 假设你的单元格点击事件绑定到这个方法 @IBAction func cellTapped(_ sender: UIButton) { delegate?.searchCategoryCellDidTap(self) } }
- 让
SearchViewController遵守代理协议,并在创建cell时设置代理:
class SearchViewController: UICollectionViewController, SearchCategoryRowCellDelegate { override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SearchCategoryRowCell", for: indexPath) as! SearchCategoryRowCell cell.delegate = self return cell } // 实现代理方法,在这里触发Segue func searchCategoryCellDidTap(_ cell: SearchCategoryRowCell) { // 先拿到当前cell对应的数据源 guard let indexPath = collectionView.indexPath(for: cell) else { return } let selectedCategory = yourDataArray[indexPath.item] // 替换成你的数据源数组 // 由ViewController触发Segue,并传递数据 performSegue(withIdentifier: "searchSegue", sender: selectedCategory) } // 重写prepare方法,给目标页面传数据 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "searchSegue" { let resultVC = segue.destination as! PhotoStreamViewController resultVC.selectedCategory = sender as? YourCategoryType // 替换成你的数据类型 } } }
方法二:用闭包(Closure)回调触发Segue
如果觉得代理太繁琐,闭包是更轻量的选择:
- 在
SearchCategoryRowCell里添加闭包属性:
class SearchCategoryRowCell: UICollectionViewCell { var onTap: (() -> Void)? @IBAction func cellTapped(_ sender: UIButton) { onTap?() } }
- 在
SearchViewController的cellForItemAt里设置闭包逻辑:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SearchCategoryRowCell", for: indexPath) as! SearchCategoryRowCell // 绑定闭包,在cell点击时触发Segue cell.onTap = { [weak self] in guard let self = self else { return } let selectedCategory = self.yourDataArray[indexPath.item] self.performSegue(withIdentifier: "searchSegue", sender: selectedCategory) } return cell }
同样别忘了在prepare(for:sender:)里给PhotoStreamViewController传递数据。
方法三:用通知(Notification)触发(不推荐)
这个方法耦合度很高,不利于后续维护,除非是临时测试场景才建议用:
- 在
SearchCategoryRowCell的点击事件里发送通知:
@IBAction func cellTapped(_ sender: UIButton) { NotificationCenter.default.post(name: NSNotification.Name("SearchCategoryTapped"), object: self) }
- 在
SearchViewController里监听通知并触发Segue:
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(handleCategoryTap), name: NSNotification.Name("SearchCategoryTapped"), object: nil) } @objc private func handleCategoryTap(_ notification: Notification) { guard let cell = notification.object as? SearchCategoryRowCell, let indexPath = collectionView.indexPath(for: cell) else { return } let selectedCategory = yourDataArray[indexPath.item] performSegue(withIdentifier: "searchSegue", sender: selectedCategory) } // 记得在页面销毁时移除监听 deinit { NotificationCenter.default.removeObserver(self) }
核心总结
不管用哪种方法,核心逻辑都是:让拥有Segue的SearchViewController来负责触发跳转,而不是让cell直接调用performSegue。优先选择代理或闭包,能保持代码的低耦合性,后续维护也更方便。
内容的提问来源于stack exchange,提问作者cyildirim
相关产品推荐
相关产品推荐

