UITableView数据填充异常问题排查及优化方案咨询
问题分析与解决方案
嘿,我立刻就发现你代码里的问题啦!咱们一步步来拆解:
一、Bug根源:索引传递错误
你第三个VC(ProvinceVC)的provinceData是一个一维数组,按「欧洲→亚洲→非洲…」的顺序存放了所有国家的拆分片段。但从第二个VC(CountryVC)跳转时,你传递的indexPath.row是当前大洲内的局部索引——比如亚洲第一个国家Thailand在亚洲数组里是索引0,但在全局国家列表里是第5个(索引5)。这就导致你选其他大洲的国家时,第三个VC始终拿的是欧洲对应局部索引的拆分数据,自然就错了!
二、快速修复方案
只需要修改CountryVC的didSelectRowAt方法,计算全局国家索引再传递给ProvinceVC:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // 计算全局索引:累加当前大洲之前所有大洲的国家数量 + 当前大洲内的索引 var globalCountryIndex = 0 for i in 0..<continentIndex { globalCountryIndex += countryData[i].count } globalCountryIndex += indexPath.row let provinceVC = ProvinceVC() provinceVC.customInit(countryIndex: globalCountryIndex, title: countryData[continentIndex][indexPath.row]) self.navigationController?.pushViewController(provinceVC, animated: true) tableView.deselectRow(at: indexPath, animated: true) }
这样传递过去的就是正确的全局索引,第三个VC就能匹配到对应国家的拆分数据了。
三、更优实现方式:用结构化数据替代独立数组
当前用多个独立数组(continentData/countryData/provinceData)来维护层级数据,很容易出现索引不匹配的问题,而且后续新增/修改数据时需要同步修改多个数组,维护成本极高。推荐用结构体组织层级数据,直接传递数据对象而非索引:
1. 定义数据模型
// 定义大洲、国家的结构化数据 struct Continent { let name: String let countries: [Country] } struct Country { let name: String let nameSegments: [String] // 对应原有的拆分片段 }
2. 第一个VC(大洲列表)修改
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { @IBOutlet weak var TableView: UITableView! // 初始化完整的层级数据 let continents: [Continent] = [ Continent(name: "Europe", countries: [ Country(name: "Germany", nameSegments: ["Ger","ma","ny"]), Country(name: "France", nameSegments: ["Fr","a","nce"]), Country(name: "Italy", nameSegments: ["Ita","ly"]), Country(name: "Spain", nameSegments: ["Spa","in"]), Country(name: "Sweden", nameSegments: ["Swe","den"]) ]), Continent(name: "Asia", countries: [ Country(name: "Thailand", nameSegments: ["Tha","il","and"]), Country(name: "Singapore", nameSegments: ["Si","nga","po","re"]), Country(name: "China", nameSegments: ["Chi","na"]), Country(name: "Philippines", nameSegments: ["Phi","li","pp","ines"]), Country(name: "Japan", nameSegments: ["Ja","pan"]) ]), // 其他大洲数据以此类推... Continent(name: "Africa", countries: [ Country(name: "Zambia", nameSegments: ["Za","mb","ia"]), Country(name: "Egypt", nameSegments: ["Egy","pt"]), Country(name: "Kenya", nameSegments: ["Ke","nya"]), Country(name: "Nigeria", nameSegments: ["Ni","ge","ria"]), Country(name: "Morocco", nameSegments: ["Mo","ro","cco"]) ]), Continent(name: "North America", countries: [ Country(name: "Canada", nameSegments: ["Ca","na","da"]), Country(name: "USA", nameSegments: ["USA"]), Country(name: "Mexico", nameSegments: ["Me","xi","co"]), Country(name: "Jamaica", nameSegments: ["Ja","ma","ica"]), Country(name: "Dominica", nameSegments: ["Do","mi","ni","ca"]) ]), Continent(name: "South America", countries: [ Country(name: "Argentina", nameSegments: ["Ar","ge","nt","ina"]), Country(name: "Peru", nameSegments: ["Pe","ru"]), Country(name: "Colombia", nameSegments: ["Co","lo","mb","ia"]), Country(name: "Brazil", nameSegments: ["Bra","zil"]), Country(name: "Chile", nameSegments: ["Chi","le"]) ]), Continent(name: "Australia", countries: [ Country(name: "Australia", nameSegments: ["Au","st","ra","lia"]), Country(name: "New Zealand", nameSegments: ["New","Zea","la","nd"]), Country(name: "Fiji", nameSegments: ["Fi","ji"]), Country(name: "Solomon Islands", nameSegments: ["So","lo","mon","Is","la","nds"]) ]) ] override func viewDidLoad() { super.viewDidLoad() } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return continents.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "continentCell", for: indexPath) cell.textLabel?.text = continents[indexPath.row].name return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedContinent = continents[indexPath.row] let countryVC = CountryVC() countryVC.continent = selectedContinent countryVC.title = selectedContinent.name self.navigationController?.pushViewController(countryVC, animated: true) tableView.deselectRow(at: indexPath, animated: true) } }
3. 第二个VC(国家列表)修改
class CountryVC: UIViewController,UITableViewDataSource, UITableViewDelegate { @IBOutlet weak var tableView: UITableView! // 直接接收完整的大洲数据对象 var continent: Continent! override func viewDidLoad() { super.viewDidLoad() self.tableView.dataSource = self self.tableView.delegate = self let nib = UINib(nibName:"CountryCell", bundle: nil) tableView.register(nib, forCellReuseIdentifier: "countryCell") } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return continent.countries.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "countryCell", for: indexPath) as! CountryCell cell.textLabel?.text = continent.countries[indexPath.row].name return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedCountry = continent.countries[indexPath.row] let provinceVC = ProvinceVC() provinceVC.country = selectedCountry provinceVC.title = selectedCountry.name self.navigationController?.pushViewController(provinceVC, animated: true) tableView.deselectRow(at: indexPath, animated: true) } }
4. 第三个VC(拆分片段列表)修改
class ProvinceVC: UIViewController, UITableViewDataSource,UITableViewDelegate { @IBOutlet weak var tableView: UITableView! // 直接接收完整的国家数据对象 var country: Country! override func viewDidLoad() { super.viewDidLoad() self.tableView.dataSource = self self.tableView.delegate = self let nib = UINib(nibName:"ProvinceCell", bundle: nil) tableView.register(nib, forCellReuseIdentifier: "provinceCell") } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return country.nameSegments.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "provinceCell", for: indexPath) as! ProvinceCell cell.textLabel?.text = country.nameSegments[indexPath.row] return cell } }
这种实现方式的优势:
- 数据结构清晰:大洲→国家→拆分片段的层级关系一目了然,彻底避免索引不匹配的问题
- 维护成本低:新增/修改数据时只需要修改一处模型数据,不用同步多个数组
- 代码可读性高:直接传递数据对象,逻辑更直观,后续调试也更方便
内容的提问来源于stack exchange,提问作者The_Ogre
相关产品推荐
相关产品推荐

