ios - 使用字符串数组的数组生成表格 View

标签 ios swift3

我有一个 CSV 文件,我想将其导入到表格 View 中,如下所示。

enter image description here

我想要标题头灯 雨刷 保险杠扰流板 作为该部分的文本和每个部分下方列出的每列的值。

所以 TableView 应该看起来像:

头灯
123
10

雨刮器
456
11

保险杠
789
12

扰流器
999
第888章

到目前为止,我的 CSV 导入器正在返回字符串 [[String]] 数组的数组

我的代码如下

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

@IBOutlet weak var tableView: UITableView!

@IBAction func buttonPressed(_ sender: Any) {
    print(bins)
}

var bins = [[String]]()

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.delegate = self
    tableView.dataSource = self

    importCsv()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

//MARK: -Table View Delegate & DataSource



func numberOfSections(in tableView: UITableView) -> Int {
    return self.bins.count > 0 ? self.bins[0].count : 0
}



func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.bins.count
}



func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "BinCell")!


    let bin = self.bins[indexPath.row]
    cell.textLabel?.text = bin[0]
    return cell
}

func importCsv() -> Void {
    let path =  "/Users/philipchan/Downloads/test.csv"
    let defaultImporter = CSVImporter<[String]>(path: path)

    defaultImporter.startImportingRecords{ $0 }.onFinish { importedRecords in
        self.bins = importedRecords
        print(self.bins)
        self.tableView.reloadData()
    }
}

}

这是我打印到输出后得到的二维数组。

[["Headlight", "Wiper", "Bumper", "spoiler"], ["123", "456", "789", "999"], ["10", "11", "12", "888"]]

在表格 View 中渲染这个二维数组的正确方法是什么?

最佳答案

表格 View 不显示 2D 数据。它们显示一个一维列表,该列表可能会也可能不会分为几个部分。

如果是我,我只需要显示 4 列数据,我可能会创建每个单元格中有 4 个标签的单元格,以及显示列标题的标题,就像您在你的帖子的开头。这似乎是显示数据的最清晰方式。

无论如何,回答你的问题:

您的数据格式有点奇怪。

它按行排列,然后按每行数组内的部分排列。为了让事情变得更加困惑,您的部分标题位于数组的第一个位置。

通常,您希望数据的外部数组是节,然后内部数组包含给定节中每一行的数据。这样,每个部分的行数就可以不同。

您可能应该“剥离”部分标题,然后使用数组的其余部分提供 TableView 的数据源方法。像这样的事情:

var sectionTitles: [String]!
var tableData: [[String]]!

/**
 This is the input data for our table view. The section titles are in the first array.
 Use a DidSet method so that if the input "bins" variable changes, we format the data
 And reload the table
 */
var bins: [[String]]? {
  
  //If the bins array changed, parse it's data.
  didSet {
    if let bins = bins {
      
      //Peel off the section titles into a separate array
      sectionTitles = bins[0]
      
      //Remove the section titles from the tableData array
      tableData = Array(bins.dropFirst(1))
      
      //Tell the table view to reload itself.
      tableView.reloadData()
    }
  }
}

override func viewDidLoad() {
  super.viewDidLoad()
  
  bins = [
    ["Headlight", "Wiper", "Bumper", "Spoiler"],
    ["123", "456", "789", "999"],
    ["10", "11", "12", "888"]
  ]
}

override func numberOfSections(in tableView: UITableView) -> Int {
  return sectionTitles?.count ?? 0
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  return tableData.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
  let row = indexPath.row
  let section = indexPath.section
  cell?.textLabel?.text = tableData[row][section]
  return cell!
}

override func tableView(_ tableView: UITableView,
                        titleForHeaderInSection section: Int) -> String {
  return sectionTitles[section]
}

编辑:

上面的代码可以工作,但是按行以及每行中的部分存储数据是错误的。 TableView 被设计为具有任意数量的部分,然后每个部分可以在该部分中具有不同数量的行。当您将数据存储为行数组和每行内的部分数据时,您不能这样做。您可以改为拥有给定的行数,然后在每行中设置可变数量的部分,这不是表格 View 的工作方式。

鉴于您正在从 CSV 文件读取数据,您可能对输入格式没有太多选择,但您当然可以将其重组为按部分组织,然后按每个部分中的行组织。以下是与上面等效的代码,但以更有意义的方式重组数据:

var sectionTitles: [String]!
var tableData: [[String]]!

/**
 This is the input data for our table view. The section titles are in the first array.
 Use a DidSet method so that if the input "bins" variable changes, we format the data
 And reload the table
 */
var bins: [[String]]? {
  
  //If the bins array changed, parse it's data.
  didSet {
    if let bins = bins {
      
      //Peel off the section titles into a separate array
      sectionTitles = bins[0]
      
      //Remove the section titles from the tableData array
      let inputData  = Array(bins.dropFirst(1))
      
      //The code below restructures the arrays to be "section major". It assumes the arrays are not
      //"jagged" and will crash if they ARE jagged.
      
      //Create a new array of arrays for the output
      var output = [[String]]()
      let rows = inputData.count
      let sections = inputData.first?.count ?? 0
      for section in 0..<sections {
        
        //Create an array for this section
        var aSection = [String]()
        for row in 0..<rows {
          //populate this section with an entry from each row
          aSection.append(inputData[row][section])
        }
        //Add the finished section to the output array
        output.append(aSection)
      }
      
      tableData = output
      //Tell the table view to reload itself.
      tableView.reloadData()
    }
  }
}

override func viewDidLoad() {
  super.viewDidLoad()
  
  bins = [
    ["Headlight", "Wiper", "Bumper", "Spoiler"],
    ["123", "456", "789", "999"],
    ["10", "11", "12", "888"]
  ]
}

override func numberOfSections(in tableView: UITableView) -> Int {
  return sectionTitles?.count ?? 0
}

override func tableView(_ tableView: UITableView,
                        numberOfRowsInSection section: Int) -> Int {
  guard tableData.count > section else {
    return 0
  }
  return tableData[section].count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
  let row = indexPath.row
  let section = indexPath.section
  cell?.textLabel?.text = tableData[section][row]
  return cell!
}

override func tableView(_ tableView: UITableView,
                        titleForHeaderInSection section: Int) -> String {
  return sectionTitles[section]
}

编辑#2:

重新阅读上面的答案后,我建议更新该方法。拥有一个节标题数组,然后一个单独的节/行表数据的二维数组似乎很脆弱。 (节标题的计数可能与二维数组中节的计数不同。)

相反,我建议为每个部分创建一个结构(称为SectionData),其中包含部分标题和该部分的行数据数组。然后我将创建一个SectionData 数组。

这样您就不必维护两个单独的数组并保持它们的项目计数同步。

struct SectionData: {
   var sectionTitle: String
   var rowData: [RowData]
}

struct RowData {
    var rowString: String
    var rowValue: Int // Some value that you display for each row
    // More row data could go here
}

var sections = [SectionData]()

关于ios - 使用字符串数组的数组生成表格 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40429955/

相关文章:

ios - 将函数转换为 Swift 3 的奇怪问题

ios - 主 - 详细项目未按预期工作

按下字母时 iOS 搜索栏关闭

ios - 当通话状态栏可见时,UIButtons 的点击区域会发生变化

ios - 如何在 iOS 中存储应用程序设置,如 INI/CONF?

swift - UserDefaults() 和 UserDefaults.standard 之间的区别

swift - 将 xib 文件加载到自定义 NSView 中会嵌入到另一个自定义 NSView 中

iphone - 当 UIButton 被拖动到屏幕的某个点时触发事件? objective-c

ios - 使用谷歌地图 iOS SDK 按照路线创建区域

ios - 为什么我在发布之前创建的 CGMutablePathRef 时会收到 SIGABRT?