2017-01-19 3 views
0

hinzufügen Ich muss den Inhalt eines JSON und Sortieren nach Datum (Abschnitte) auflisten. Bis jetzt habe ich es geschafft, den JSON erfolgreich zu bekommen und den Hauptinhalt (Name und Stunde) aufzulisten, aber ich muss nach Datum als Abschnitt sortieren.Wie Abschnitt zu UITableView programmgesteuert in swift 3

EDIT: Wenn ich mehr als 100 „Produkte“ haben (JSON-Objekte) und in einigen der Zeitpunkt wiederholt wird (wie in den ersten beiden Objekte der json unten), dann will ich diese Elemente in sein ein Abschnitt mit dem Datum als Titel jedes Abschnitts.

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"} 
] 

Hauptklasse:

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") 

    } 


} 

Antwort

1

Hier können Sie Codebeispiel haben (Paste in hinzufügen Pl ayground und viel spaß)

//: 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

Vielen Dank. Ich habe es versucht und es funktioniert. Die Daten erscheinen als Abschnittstitel, aber leider nicht in der Reihenfolge (wie es im json ist). Ich weiß nicht, was passieren könnte. /: – user5195185

+0

Dies liegt daran, dass das Wörterbuch die Reihenfolge der Schlüssel nicht garantiert. Sie können in https://github.com/lukaskubanek/OrderedDictionary nachsehen. Überprüfen Sie auch meine aktualisierte Antwort, jetzt hat Speicherschlüssel in Array, um die gleiche Reihenfolge der Schlüssel wie in der JSON-Datei zu halten. –

+0

Wow! Ich danke dir sehr! – user5195185

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

Mit dieser Funktion können Sie die Abschnitte programmatisch

+0

Danke, aber was ist, wenn ich nicht weiß, wie viele "Abschnitte" ich habe? (Abhängig von dynamischem JSON) – user5195185

+0

Verwenden Sie anstelle von 5 eine Instanzvariable. Füllen Sie diese Variable jedes Mal auf, wenn Sie Ihre JSON-Struktur analysieren. – Xvolks

+0

Nun, nehme ich an: 'return section.count', das ist nicht genug, oder? – user5195185

Verwandte Themen