2017-01-19 1 views
0

Мне нужно перечислить содержимое json и отсортировать по дате (разделы). До сих пор мне удалось успешно запустить json и перечислить основной контент (имя и час), но мне нужно сортировать по дате в качестве раздела.Как добавить раздел в UITableView программно в swift 3

EDIT: Если у меня есть более чем 100 «пунктов» (JSON объектов) и в некоторых дата повторяется (как и в первых двух объектов ниже JSON), то я хочу, чтобы эти элементы, чтобы быть в раздел с датой в качестве названия каждого раздела.

Json:

[ 
{"date_raw":"1/18/2017 12:00:00 AM","name":"Hello 2","hour":"12:00 - 14:00","audio_url":"http://example.com/file2.mp4"}, 
{"date_raw":"1/18/2017 12:00:00 AM","name":"Hello 1","hour":"10:00 - 12:00","audio_url":"http://example.com/file1.mp4"}, 
{"date_raw":"1/17/2017 12:00:00 AM","name":"Hello","hour":"10:00 - 12:00","audio_url":"http://example.com/file.mp4"}, 
{"date_raw":"1/16/2017 12:00:00 AM","name":"Hello","hour":"10:00 - 12:00","audio_url":"http://example.com/file.mp4"} 
] 

Главный класс:

class MyVC: UIViewController, UITableViewDelegate, UITableViewDataSource { 

    @IBOutlet weak var tableView: UITableView! 

    // date_raw 
    var section: [String] = [] 

    // date_raw, name, hour, audio_url 
    var items: [(String, String, String, String)] = [] 

    var dateV:String = "" 

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

    } 


    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 

     let cell:UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "cell") 

     cell.textLabel!.text = items[indexPath.row].1 // get name 
     cell.detailTextLabel!.text = items[indexPath.row].2 // get hour 

     return cell; 
    } 


    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 
     print(items[indexPath.row]) 

    } 


    func getJson(_ url:String) { 

     // Asynchronous Http call to your api url, using NSURLSession: 
     URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { (data, response, error) -> Void in 

      if error != nil || data == nil { 

       print("error") 

      } else { 


       do { 

        let json:NSArray = try (JSONSerialization.jsonObject(with: data!, options:JSONSerialization.ReadingOptions.mutableContainers) as? NSArray)! 

        for i in 0...json.count-1 { 

         if let date_raw = (json[i] as AnyObject).value(forKey: "date_raw") as? String, 
          let name = (json[i] as AnyObject).value(forKey: "name") as? String, 
          let hour = (json[i] as AnyObject).value(forKey: "hour") as? String, 
          let audio_url = (json[i] as AnyObject).value(forKey: "audio_url") as? String { 

          if date_raw != self.dateV { 
           self.section.append(date_raw) 
           self.dateV = date_raw; 
          } 

          self.items.append(date_raw, name, hour, audio_url) 

         } 
        }//End for 

        //print(self.section) 
        self.do_table_refresh(); 

       } catch { 
        print("error") 
       } 

      } 

     }).resume() 
     // TODO: butonu disable et 
    } 


    func do_table_refresh() { 
     DispatchQueue.main.async(execute: { 
      self.tableView.reloadData() 
      self.tableView.isHidden = false 
      return 
     }) 
    } 


    override func viewDidLoad() { 
     super.viewDidLoad() 

     tableView.delegate  = self 
     tableView.dataSource = self 
     tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell") 
     tableView.isHidden = true 

     getJson("http://example.com/my-json-file.json") 

    } 


} 

ответ

1

Вот вам пример кода (вставить Pl ayground и получайте удовольствие)

//: Playground - noun: a place where people can play 

import UIKit 
import PlaygroundSupport 

PlaygroundPage.current.needsIndefiniteExecution = true 

struct Model { 
    let date: String 
    let name: String 
    let hour: String 
    let audioUrl: String 
} 

class HelpViewController: UITableViewController { 

    let jsonData = "[{\"date_raw\":\"1/18/2017 12:00:00 AM\",\"name\":\"Hello 2\",\"hour\":\"12:00 - 14:00\",\"audio_url\":\"http://example.com/file2.mp4\"},{\"date_raw\":\"1/18/2017 12:00:00 AM\",\"name\":\"Hello 1\",\"hour\":\"10:00 - 12:00\",\"audio_url\":\"http://example.com/file1.mp4\"},{\"date_raw\":\"1/17/2017 12:00:00 AM\",\"name\":\"Hello\",\"hour\":\"10:00 - 12:00\",\"audio_url\":\"http://example.com/file.mp4\"},{\"date_raw\":\"1/16/2017 12:00:00 AM\",\"name\":\"Hello\",\"hour\":\"10:00 - 12:00\",\"audio_url\":\"http://example.com/file.mp4\"}]" 

    var data = [String: [Model]]() 
    var keys = [String]() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     tableView.register(UITableViewCell.self, forCellReuseIdentifier: "TestCell") 
     loadData() 
    } 

    func loadData() { 
     guard let jsonData = jsonData.data(using: .utf8), 
      let json = try? JSONSerialization.jsonObject(with: jsonData, options: .allowFragments), 
      let jsonArray = json as? [[String: Any]] 
     else { return } 

     // Map json to array of Models 
     let mappedData = jsonArray.flatMap { (elem) -> Model? in 
      guard let dateRaw = elem["date_raw"] as? String, 
       let name = elem["name"] as? String, 
       let hour = elem["hour"] as? String, 
       let audioUrl = elem["audio_url"] as? String else { return nil } 

      return Model(date: dateRaw, name: name, hour: hour, audioUrl: audioUrl) 
     } 

     // Create a dictionary from array of Models 
     // Each key == section (model.date), will contain array of associated with this key models 
     data = mappedData.reduce([String: [Model]]()) { (result, element) -> [String: [Model]] in 

      var res = result 
      if res[element.date] == nil { 
       res[element.date] = [element] 
       self.keys += [element.date] 
      } else { 
       res[element.date]! += [element] 
      } 
      return res 
     } 

     tableView.reloadData() 
    } 

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     if keys.count < 1 { return 0 } 

     let key = keys[section] 
     return data[key]?.count ?? 0 
    } 

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

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

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

     let key = keys[indexPath.section] 
     let model = data[key]?[indexPath.row] 
     if let model = model { 
      cell.textLabel?.text = model.name 
     } 

     return cell 
    } 

} 

let helpViewController = HelpViewController() 
helpViewController.view.frame = CGRect(x: 0, y: 0, width: 320, height: 400) 

PlaygroundPage.current.liveView = helpViewController.view 
+0

Спасибо. Я пробовал и работает. Даты отображаются как заголовок раздела, но, к сожалению, не в порядке (как в json). Я не знаю, что может случиться. /: – user5195185

+0

Это потому, что Словарь не гарантирует порядок ключей. Вы можете посмотреть https://github.com/lukaskubanek/OrderedDictionary. Также проверьте мой обновленный ответ, теперь он хранит ключи в массиве, чтобы сохранить тот же порядок ключей, что и в json-файле. –

+0

Вау! Спасибо огромное! – user5195185

2
func numberOfSections(in tableView: UITableView) -> Int 
{ 
    return 5 // number of sections 
} 

Используйте эту функцию, чтобы добавить разделы программно

+0

Спасибо, но что, если я не знаю, сколько «секций» у меня будет? (Зависит от динамического json) – user5195185

+0

Используйте переменную экземпляра вместо 5. Заполняйте эту переменную каждый раз, когда вы разбираете структуру json. – Xvolks

+0

Ну, допустим, я использую: 'return section.count', этого недостаточно, не так ли? – user5195185