Show JSON as TableView Section and TableView row in Swift 4.2 without Decodable?

后端 未结 2 1973
南旧
南旧 2021-01-27 09:06

I have below JSON response array with key \"events\"

{
  \"events\": [
 {
  \"name\": \"event foo\",
  \"date\": \"2020-05-22\",
  \"time\": \"7:00\",
  \"am_or_         


        
相关标签:
2条回答
  • 2021-01-27 09:32

    I did above solutions using Alamofire 5.0 and below is my complete solutions so that it can help someone:

    // Create a Modal Class of name "Event"

    class Event {
        var name: String?
        var date: String?
        var time: String?
        var amOrPm: String?
        var day: String?
        var description: String?
    
    
    
    init(dic: [String: Any]) {
        if let name = dic["name"] as? String {
            self.name = name
        }
        if let date = dic["date"] as? String {
            self.date = date
        }
        if let time = dic["time"] as? String {
            self.time = time
        }
        if let amOrPm = dic["am_or_pm"] as? String {
            self.amOrPm = amOrPm
        }
        if let day = dic["day"] as? String {
            self.day = day
        }
        if let description = dic["description"] as? String {
            self.description = description
        }
        }
    }
    

    // Creating a Global Class for URL

    import Alamofire
    
    class HttpManager {
        struct Constants {
            static let baseUrl = "https://my-json-server.typicode.com/JCkshone/jsonTest"
        }
    
        func getEvents(handledResponse: @escaping (_ data: [[String: Any]])->()) {
            let request = AF.request("\(Constants.baseUrl)/db")
    
            request.responseJSON { (response: AFDataResponse<Any>) in
                guard let data = response.value as? [String: Any] else { return }
                if let events: [[String: Any]] = data["events"] as? [[String: Any]] {
                    handledResponse(events)
                }
            }
        }
    }
    

    // Finally ViewController.swift

    struct SectionEvent {
        var sectionName: String
        var evenst: [Event]
    }
    
    class ViewController: UIViewController {
        @IBOutlet weak var tableView: UITableView!
        let http  = HttpManager()
        var events: [Event] = []
        var tableViewData: [SectionEvent] = []
        let cell = "cellId"
    
        override func viewDidLoad() {
            super.viewDidLoad()
            fetchData()
            initTableView()
        }
    
        func fetchData() {
            http.getEvents { (data: [[String : Any]]) in
                data.forEach { item in
                    self.events.append(Event(dic: item))
                }
                self.buildData()
            }
        }
    
        func buildData() {
            events.forEach { event in
    
            let validation = validateEventExist(event: event)
            if !validation.exist {
                tableViewData.append(SectionEvent(sectionName: event.date ?? "", evenst: [event]))
            } else {
                tableViewData[validation.position].evenst.append(event)
            }
        }
        self.tableView.reloadData()
    }
    
    func validateEventExist(event: Event) -> (exist: Bool, position: Int) {
        let filterData = tableViewData.filter {$0.sectionName == event.date}
        let index = tableViewData.firstIndex { $0.sectionName == event.date}
        return (filterData.count > 0, index ?? 0)
    }
    
        func initTableView() {
            tableView.register(UITableViewCell.self, forCellReuseIdentifier: cell)
            tableView.tableHeaderView = UIView()
        }
    }
    
    extension ViewController: UITableViewDataSource, UITableViewDelegate {
    
    
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        tableViewData[section].sectionName
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        tableViewData.count
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        tableViewData[section].evenst.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
        if let name = tableViewData[indexPath.section].evenst[indexPath.row].name, let description = tableViewData[indexPath.section].evenst[indexPath.row].description {
            cell.textLabel?.text = "\(name) \n\(description)"
            cell.textLabel?.numberOfLines = 0
        }
    
        return cell
       }
    }
    
    0 讨论(0)
  • 2021-01-27 09:46

    First things first, you'll need to create a Model, so that you can transform your JSON into usable objects. To do that, good practice is to use the Codable protocol, which will automatically map your JSON keys to a struct/class variable

    struct Event: Codable {
        var name: String!
        var date: String!
        var time: String!
        var am_or_pm: String!
        var day: String!
        var description: String!
    }
    
    struct Events: Codable {
        var events: [Event]!
    }
    

    Now that you have the model that will be generated from the JSON, you need to decode your JSON into your model. There are plenty of ways to do it, I like to use JSONEncoder/JSONDecoder. So, let's say your JSON string is stored in the variable myJsonString, you would need to

    if let jsonData = myJsonString.data(using: .utf8) {
        do {
            let events = try JSONDecoder().decode(Events.self, from: jsonData)
        } catch {
            print("Error decoding json!", error.localizedDescription)
        }
    } else {
        print("Failed to get bytes from string!")
    }
    

    We can, now turn that code block into a function that returns Events, or nil, if it fails to decode the string.

    func getEvents(from jsonString: String) -> Events? {
        guard let jsonData = myJsonString.data(using: .utf8) else { return nil }
        return try? JSONDecoder().decode(Events.self, from: jsonData)
    }
    

    Cool! We can easily get our events based on a JSON string now! All we gotta do next is populate the tableView! To do that, we can create a few functions in our Events struct that will return just what we need to populate our section. The first function will return the sections for our tableView, and the second will return all items for a given section. Let's modify the Events struct

    struct Events: Codable {
        var events: [Event]!
    
        func getSections() -> [String] {
            return Array(Set(self.events.map { $0.date }))
        }
    
        func getItems(forSection dateSection: String) -> [Section] {
            return self.events.filter {$0.date == dateSection}
        }
    }
    

    Now, in your TableView datasource class, you need to use the model we created. I`ll do an example for you

    class YourTableView: UIViewController, UITableViewDataSource, UITableViewDelegate {
        // This is loaded from the getEvents function!
        var events: Events!
    
       func numberOfSections (in tableView: UITableView) -> Int {
            return self.events.getSections().count
        }
    
       func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            let dateSection = self.events.getSections()[section]
            return self.events.getItems(forSection: dateSection ).count
        }
    
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let dateSection = self.events.getSections()[indexPath.section]
            let currentEvent = self.getItems(forSection: dateSection)
    
             // Build your cell using currentEvent
        }
    }
    

    You are probably getting those JSONs from the web, so you have to handle a "loading" state, where you are returning the JSON from the API. That can easily be done by turning the events var into a optional, setting it when you get your JSON and reloading data from your tableView

    0 讨论(0)
提交回复
热议问题