我正在尝试使用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]()。如果我是你,我还将重组整个模型,这似乎过于复杂。

07-26 02:30