【问题标题】:Group and Sort Dictionary Data in TableViewController with Swift使用 Swift 在 TableViewController 中对字典数据进行分组和排序
【发布时间】:2015-11-16 22:16:57
【问题描述】:

我有一个如下所示的 Dictionary 数据结构,我试图在我的 TableViewController 中对它们进行分组,以便 A 组显示以 title = A 开头的 MyData 并在同时显示 sectionIndexTitlesForTableView 以及从 Title 获得的可用字母。

[这就是我想要实现的]

我试图从我的字典中的标题元素中删除所有第一个字母,并使用下面的代码将它们保存在一个集合中,但是当我运行我的应用程序时,我的表中出现了重复的结果。

我对 swift 还是很陌生,很高兴得到指导,了解如何实现这一目标。

这是我的字典数据:

var data: [[String:AnyObject]] =

[
  [
    "id": "1",
    "title": "A Title",
    "alphabet": "A",
    "Detail": "This is a String"
  ],      
  [
    "id": "2",
    "title": "A Title Again",
    "alphabet": "A",
    "Detail": "This is a String"
  ],
  [
    "id": "3",
    "title": "B Title",
    "alphabet": "B",
    "Detail": "This is a String"
  ],
  [
    "id": "4",
    "title": "B Title Again",
    "alphabet": "B",
    "Detail": "This is a String"
  ]
]

这是我的尝试:

class Index: UITableViewController {

var MyData = data

var letters = Set<String>()


override func viewDidLoad() {
    super.viewDidLoad()
    for element in MyData {
        var title = element["title"] as? String
        let letter = title?.substringToIndex(advance(title!.startIndex, 1))         
        letters.insert(letter!)
    }


  MyData =   MyData.sort { element1, element2 in
        let title1 = element1["title"] as? String
        let title2 = element2["title"] as? String

        return title1 < title2
    }

}

// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return letters.count
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return self.MyData.count
}


override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell?

        cell!.textLabel?.text = (MyData[indexPath.row]["title"] as! String)

    return cell!

}

【问题讨论】:

    标签: ios xcode swift cocoa-touch xcode7-beta5


    【解决方案1】:

    问题是numberOfRowsInSection 必须返回每个部分的行数,在您的示例中,第 0 部分为 2,第 1 部分为 2

    您可以使用键值编码方法valueForKey收集您的字母集,这经常被误认为objectForKey
    objectForKey 不同,它为给定键返回一个值 valueForKey 返回数组中所有成员的键 alphabet 的值。

    此代码创建一个Set 的字母以清除重复项,将其转回Array 并对其进行排序。

    let letters = (data as NSArray).valueForKey("alphabet") as! [String]
    let filteredLetters = Set<String>(letters)
    let sortedLetters = Array(filteredLetters).sorted {$0 < $1}
    

    如果alphabet 的所有值(以及其他键)都保证为String,则无需将它们强制转换为可选项。

    那么在numberOfRowsInSection你要过滤每个section的item数

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
       return data.filter { ($0["alphabet"] as! String) == sortedLetters[section] }.count
    }
    

    请注意,表达式 sortedLetters[section] 不需要强制转换,因为编译器知道这是 String 的数组。

    当然,您还必须为cellForRowAtIndexPath 中的部分检索适当的项目,这非常昂贵,因为主数组将被过滤多次。
    我建议将viewDidLoad() 中的data 转换为一个新字典,其中字母作为键,数组包含以该特定字母开头的项目作为值。这是关于速度和性能的最佳解决方案。

    这里是一个完整的解决方案(不显示用于快速搜索的字母)

    class TableViewController: UITableViewController {
    
      let data: [[String:String]] =
    
      [
        [
          "id": "1",
          "title": "A Title",
          "alphabet": "A",
          "Detail": "This is a String"
        ],
        [
          "id": "2",
          "title": "A Title Again",
          "alphabet": "A",
          "Detail": "This is a String"
        ],
        [
          "id": "3",
          "title": "B Title",
          "alphabet": "B",
          "Detail": "This is a String"
        ],
        [
          "id": "4",
          "title": "B Title Again",
          "alphabet": "B",
          "Detail": "This is a String"
        ]
      ]
    
    
      var letters = [String]()
      var dataSource = [String:AnyObject]()
    
      override func viewDidLoad() {
        super.viewDidLoad()
    
        for value in data  {
          let letter = value["alphabet"]!
          if dataSource[letter] == nil {
            letters.append(letter)
            dataSource[letter] = [[String:AnyObject]]()
          }
          var array = dataSource[letter] as! [[String:AnyObject]]
          array.append(value)
          dataSource.updateValue(array, forKey: letter)
        }
        letters.sorted {$0 < $1}
        tableView.reloadData()
    
      }
    
      // MARK: - Table view data source
    
      override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return letters.count
      }
    
      override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let letter = letters[section]
        return dataSource[letter]!.count
      }
    
    
      override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
    
        let letter = letters[indexPath.section]
        let letterArray = dataSource[letter]! as! [[String:AnyObject]]
        let item = letterArray [indexPath.row]
        if let title = item["title"] as? String {
          cell.textLabel?.text = title
        }
        return cell
      }
    
      override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return letters[section]
      }
    }
    

    【讨论】:

    • 非常感谢您的回复。我希望你能指导我的代码,以便让我更好地理解。我只是 Swift 的初学者。
    • 您的代码无法以这种方式工作,并且基于您的代码提供解决方案太复杂了。我会发布一个完整的解决方案
    猜你喜欢
    • 2018-07-17
    • 1970-01-01
    • 2016-07-14
    • 2021-08-12
    • 2017-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-15
    相关资源
    最近更新 更多