UITableView中Delegate Method未触发及数据传递异常问题
iOS数据传递问题排查与修复
问题
尝试从ViewController向UITableViewCell传递数据时遇到两个问题:
- 自定义代理方法
getDeviceData未被调用 - UITableViewCell内CollectionView的
numberOfItemsInSection方法中deviceArray为nil,但didSelectItemAt方法中deviceArray能正常获取数据
相关代码
ViewController代码
protocol homeVCdelegate { func getDeviceData(_ controller : HomeViewController, deviceData : [device]) } // 注册UITableView shortcutTable.delegate = self shortcutTable.dataSource = self shortcutTable.register(UINib(nibName: "shortcutCell", bundle: nil), forCellReuseIdentifier: "shortcutCell") // 声明代理 var delegate : homeVCdelegate? // API请求内调用代理方法 DispatchQueue.main.async { self.allDevices = finalData2.owndevices + finalData2.deldevices self.allDevices = self.allDevices.sorted(by: {$0.givenName.lowercased() < $1.givenName.lowercased()}) self.delegate?.getDeviceData(self, deviceData: self.allDevices) self.shortcutTable.reloadData() self.sendTopicListSocket(topics: topicList) } // HomeVC中UITableView的cellForRowAt实现 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = shortcutTable.dequeueReusableCell(withIdentifier: "shortcutCell", for: indexPath) as! shortcutCell cell.delegate = self cell.deviceArray = self.allDevices return cell }
UITableViewCell代码
class shortcutCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { var deviceArray : Array<device>? override func awakeFromNib() { super.awakeFromNib() let homeVC = storyboard.instantiateViewController(withIdentifier: "HomeViewController") as? HomeViewController homeVC!.delegate = self } func getDeviceData(_ controller: HomeViewController, deviceData: [device]) { self.deviceArray = deviceData self.deviceArray?.forEach({ device in self.deviceNames?.append(device.name) self.deviceIDs?.append(device._id) }) } // CollectionView相关方法 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { print("DEVICE ARRAY COUNT", self.deviceArray?.count as Any) return self.deviceArray?.count ?? 1 } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { print(self.deviceArray) print(indexPath.row) print(self.deviceArray?[indexPath.row].givenName) } }
解决方案
问题1:代理方法getDeviceData未被调用
原因:在shortcutCell的awakeFromNib中,你新实例化了一个HomeViewController对象并设置代理,但这个新实例和当前正在运行的HomeVC不是同一个对象。API请求是在原HomeVC中执行的,所以代理方法永远不会触发。此外,你已经在cellForRowAt中直接给cell赋值deviceArray,完全不需要代理传递数据。
修复:删除shortcutCell中awakeFromNib内的HomeVC实例化和代理代码,同时可以移除整个homeVCdelegate协议(因为没用了):
// 移除shortcutCell中的这段代码 override func awakeFromNib() { super.awakeFromNib() // 删掉以下两行 // let homeVC = storyboard.instantiateViewController(withIdentifier: "HomeViewController") as? HomeViewController // homeVC!.delegate = self } // 同时可以删除ViewController中的homeVCdelegate协议声明和delegate变量
问题2:CollectionView数据源方法中deviceArray为nil
原因:UITableViewCell复用机制下,CollectionView的数据源方法可能在deviceArray赋值前就被调用;另外,赋值deviceArray后没有主动刷新CollectionView,导致数据不同步。
修复:
- 给
shortcutCell的deviceArray添加属性观察者,值变化时自动刷新CollectionView:
class shortcutCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { var deviceArray : Array<device>? { didSet { // 替换成你的CollectionView变量名,比如collectionView self.collectionView.reloadData() // 如果需要同步deviceNames和deviceIDs,也放在这里 self.deviceNames?.removeAll() self.deviceIDs?.removeAll() self.deviceArray?.forEach({ device in self.deviceNames?.append(device.name) self.deviceIDs?.append(device._id) }) } } // ... 其他代码 }
- 修改
numberOfItemsInSection的默认返回值为0,避免显示空单元格:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { print("DEVICE ARRAY COUNT", self.deviceArray?.count as Any) return self.deviceArray?.count ?? 0 }
内容的提问来源于stack exchange,提问作者AbheshekSharma
相关产品推荐
相关产品推荐

