我正在尝试使用tableview创建可折叠菜单。调用return self.sideBars[section].movies!.count
时,函数funcOfOfRowsInSection出现错误。我没有得到的是当我选择配置文件(选项卡之一)return self.sideBars[section].movies!.count
时,它可以正常工作并显示数组。但是,当我选择设置或选项(其他选项卡)时,出现错误索引超出范围。我不确定为什么会这样。我曾尝试对设置和选项选项卡使用不同的数组,但仍超出索引范围。帮助将不胜感激!提前致谢
这是发生错误的地方
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> (Int) {
let it = String(describing: items[section])
var item = items[section]
guard item.isCollapsible else {
if (it == "ProfileViewModelAboutItem") {
return self.sideBars[section].movies!.count
}
if (it == "ProfileViewModelsettingsItem") {
return self.sideBars[section].movies!.count
}
if (it == "ProfileViewModelOptionsItem") {
return self.sideBars[section].movies!.count
}
return item.rowCount
}
if item.isCollapsed {
return 0
} else {
if (it == "ProfileViewModelAboutItem") {
return self.sideBars[section].movies!.count // This works fine
}
if (it == "ProfileViewModelsettingsItem") {
return self.sideBars[section].movies!.count // This is where error occurs: Index out of range
}
if (it == "ProfileViewModelOptionsItem") {
return self.sideBars[section].movies!.count // Also here, fatal error: Index out of range
}
return item.rowCount
}
}
下面的整个代码让您有更多的了解
import Foundation
enum ProfileViewModelItemType {
case profile
case settings
case options
}
protocol ProfileViewModelItem {
var type: ProfileViewModelItemType { get }
var sectionTitle: String { get }
var rowCount:(Int) { get }
var isCollapsible: Bool { get }
var isCollapsed: Bool { get set }
}
extension ProfileViewModelItem {
var rowCount: Int {
return 1
}
var isCollapsible: Bool {
return true
}
}
class ProfileViewModel: NSObject {
var items = [ProfileViewModelItem]()
var sideBars = [sideBar]()
var reloadSections: ((_ section: Int) -> Void)?
override init() {
super.init()
let profile = sideBar(movies: [“Followers”, “Following”, “bye”], count: [“1”,”2”,“3”])
let profileItems = ProfileViewModelAboutItem(sideBars: [profile])
self.items.append(profileItems)
let about = sideBar(movies: ["Delete Account", “test”], count: [“1”,”2”])
let settingItem = ProfileViewModelsettingsItem(sideBars: [about])
self.items.append(settingItem)
let option = sideBar(movies: ["about", "FAQ"], count: [“1”,”2”])
let optionsItem = ProfileViewModelOptionsItem(sideBars: [option])
self.items.append(optionsItem)
}
}
extension ProfileViewModel: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> (Int) {
return items.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> (Int) {
let it = String(describing: items[section])
var item = items[section]
guard item.isCollapsible else {
if (it == "ProfileViewModelAboutItem") {
return self.sideBars[section].movies!.count
}
if (it == "ProfileViewModelsettingsItem") {
return self.sideBars[section].movies!.count
}
if (it == "ProfileViewModelOptionsItem") {
return self.sideBars[section].movies!.count
}
return item.rowCount
}
if item.isCollapsed {
return 0
} else {
if (it == "ProfileViewModelAboutItem") {
return self.sideBars[section].movies!.count // This works fine
}
if (it == "ProfileViewModelsettingsItem") {
return self.sideBars[section].movies!.count // This is where error occurs: Index out of range
}
if (it == "ProfileViewModelOptionsItem") {
return self.sideBars[section].movies!.count // Also here, fatal error: Index out of range
}
return item.rowCount
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = items[indexPath.section]
switch item.type {
case .profile:
if let item = item as? ProfileViewModelAboutItem, let cell = tableView.dequeueReusableCell(withIdentifier: myProfileCell.identifier, for: indexPath) as? myProfileCell {
let title = item.sideBars[indexPath.section].movies[indexPath.row]
cell.profileLabel.text = title
return cell
}
case .settings:
if let item = item as? ProfileViewModelsettingsItem, let cell = tableView.dequeueReusableCell(withIdentifier: settingsCell.identifier, for: indexPath) as? settingsCell {
let title = item.sideBars[indexPath.section].movies[indexPath.row]
cell.settingsLabel.text = title
return cell
}
case .options:
if let item = item as? ProfileViewModelOptionsItem, let cell = tableView.dequeueReusableCell(withIdentifier: optionsCell.identifier, for: indexPath) as? optionsCell {
let title = item.sideBars[indexPath.section].movies[indexPath.row]
cell.optionLabel.text = title
return cell
}
}
return UITableViewCell()
}
}
extension ProfileViewModel: UITableViewDelegate {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: HeaderView.identifier) as? HeaderView {
let item = items[section]
headerView.item = item
headerView.section = section
headerView.delegate = self
return headerView
}
return UIView()
}
}
extension ProfileViewModel: HeaderViewDelegate {
func toggleSection(header: HeaderView, section: Int) {
var item = items[section]
if item.isCollapsible {
// Toggle collapse
let collapsed = !item.isCollapsed
item.isCollapsed = collapsed
header.setCollapsed(collapsed: collapsed)
reloadSections?(section)
}
}
}
class ProfileViewModelAboutItem: ProfileViewModelItem {
var type: ProfileViewModelItemType {
return .profile
}
var sectionTitle: String {
return "My Profile"
}
var isCollapsed = true
var sideBars = [sideBar]()
var rowCount: Int {
return self.sideBars.count
}
init(sideBars: [sideBar]) {
self.sideBars = sideBars
}
}
class ProfileViewModelsettingsItem: ProfileViewModelItem {
var type: ProfileViewModelItemType {
return .settings
}
var sectionTitle: String {
return "Settings"
}
var isCollapsed = true
var sideBars = [sideBar]()
var rowCount: Int {
return self.sideBars.count
}
init(sideBars: [sideBar]) {
self.sideBars = sideBars
}
}
class ProfileViewModelOptionsItem: ProfileViewModelItem {
var type: ProfileViewModelItemType {
return .options
}
var sectionTitle: String {
return “Options”
}
var isCollapsed = true
var sideBars = [sideBar]()
var rowCount: Int {
return self.sideBars.count
}
init(sideBars: [sideBar]) {
self.sideBars = sideBars
}
}
sideBar结构
struct sideBar {
var movies: [String]
var count: [String]
init(movies: [String], count: [String]){
self.movies = movies
self.count = count
}
}
最佳答案
问题是您只填充子类的sideBars
数组。 sideBars
类的ProfileViewModel
数组永远不会填充数据,因为您只会在子类的初始化程序内部对数组进行突变。但是,在填充数据(空数组)时,请使用超类的sideBars
。
override init() {
super.init()
let profile = sideBar(movies: [“Followers”, “Following”, “bye”], count: [“1”,”2”,“3”])
let profileItems = ProfileViewModelAboutItem(settings: [profile])
self.items.append(profileItems)
self.sideBars.append(profile)
let about = sideBar(movies: ["Delete Account", “test”], count: [“1”,”2”])
let settingItem = ProfileViewModelsettingsItem(sideBars: [about])
self.items.append(settingItem)
self.sideBars.append(about)
let option = sideBar(movies: ["about", "FAQ"], count: [“1”,”2”])
let optionsItem = ProfileViewModelOptionsItem(sideBars: [option])
self.items.append(optionsItem)
self.sideBars.append(option)
}
一些一般性建议:请遵循
Swift
命名约定,即您以大写字母开头类型名称,例如struct SideBar
,并以小写驼峰命名方式来命名变量名称,例如var sideBars = [SideBar]()
。如果我是你,我还将重组整个模型,这似乎过于复杂。