【问题标题】:Swift 3 Sort / Group JSON Data into Tableview with SectionsSwift 3 将 JSON 数据排序/分组到带有部分的 Tableview 中
【发布时间】:2017-07-26 23:09:28
【问题描述】:

我需要将 JSON 数据分类/分组到 tableview 上的部分。

目前,JSON 数据无法轻易更改,因此需要在 Swift 中重新排序。

基本上,我希望它计算有多少不同的 DATES(这只是一个字符串值)并根据它对数据进行排序。然后,这些部分应该是不同的 DATES,行中的受人尊敬的文章。

表格视图应如下所示:

**January 1, 2016**
- Article A 
     - Title
     - Author
     - ETC...
- Article C
     - Title
     - Author
     - ETC...
**February 2, 2016**
- Article B
     - Title
     - Author
     - ETC...

现在 JSON 看起来像:

[
    {
        “x_author”: "",
        "excerpt" : 
            "rendered": “”
        },
        "x_featured_media" : "",
        "title": {
            "rendered": “A”
        },
        "x_date": “January 1, 2016",
    },
    {
        “x_author”: "",
        "excerpt" : 
            "rendered": “”
        },
        "x_featured_media" : "",
        "title": {
            "rendered": “B”
        },
        "x_date": “February 1, 2016",
    },
    {
        “x_author”: "",
        "excerpt" : 
            "rendered": “”
        },
        "x_featured_media" : "",
        "title": {
            "rendered": “C”
        },
        "x_date": “January 1, 2016",
    },
]

ViewController 如下所示:

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    @IBOutlet var tableview: UITableView!

    var articles: [Article]? = []

        override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        fetchArticles()
    }

    func fetchArticles() {
        let urlRequest = URLRequest(url: URL(string: "SITE")!)
        let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
            if error != nil {
                print(error)
                return
            }
            self.articles = [Article]()
            do {
                let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? AnyObject
                if let articlesFromJson = json as? [[String : AnyObject ]] {
                    for articleFromJson in articlesFromJson {
                        let article = Article()
                          if let title = articleFromJson["title"]?["rendered"] as? String, 
                              let author = articleFromJson["x_author"] as? String, 
                              let desc = articleFromJson["excerpt"]?["rendered"] as? String, 
                              let url = articleFromJson["link"] as? String, 
                              let urlToImage = articleFromJson["x_featured_media"] as? String, 
                              let date = articleFromJson["x_date"] as? String {

                            article.author = author
                            article.desc = desc
                            article.headline = title
                            article.url = url
                            article.imageUrl = urlToImage
                            article.date = date
                        }
                        self.articles?.append(article)
                     }
                }
                DispatchQueue.main.async {
                    self.tableview.reloadData()
                }
            } catch let error {
                print(error)
            }
        }
        task.resume()
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "articleCell", for: indexPath) as! articleCell
        cell.title.text = self.articles?[indexPath.item].headline
        cell.desc.text = self.articles?[indexPath.item].desc
        cell.author.text = self.articles?[indexPath.item].author
        cell.date.text = self.articles?[indexPath.item].date    
        cell.imgView.downloadImage(from: (self.articles?[indexPath.item].imageUrl!)!)
        return cell
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

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

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let webVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "web") as! WebviewViewController
        webVC.url = self.articles?[indexPath.item].url
        self.present(webVC, animated: true, completion: nil)
    }
}

Article 类如下所示:

import UIKit

class Article: NSObject {
    var headline: String?
    var desc: String?
    var author: String?
    var url: String?
    var content: String?
    var imageUrl: String?
    var date: String?
}

我该怎么做?

编辑 1:

按照 dmorrow 的建议,视图控制器现在看起来像这样:

    struct Issue {
    let dateName: String?
    var articles: [Article]?
}
struct Article {
    var headline: String?
    var desc: String?
    var author: String?
    var url: String?
    var imageUrl: String?
    var date: String?
}

var groupedArticles = [Issue]()

    override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    fetchArticles()
}

func fetchArticles() {
    let urlRequest = URLRequest(url: URL(string: "SITE")!)
    let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
        if error != nil {
            print(error)
            return
        }
        do {
            let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? AnyObject
            if let articlesFromJson = json as? [[String : AnyObject ]] {
                for articleFromJson in articlesFromJson {

                        self.groupedArticles.append(Issue(dateName: (articleFromJson["x_date"] as! String), articles: [Article(headline: (articleFromJson["title"] as! String), desc: (articleFromJson["excerpt"] as! String), author: (articleFromJson["x_author"] as! String), url: (articleFromJson["x_featured_media"] as! String), imageUrl: (articleFromJson["x_featured_media"] as! String), date: (articleFromJson["x_date"] as! String))]))                    
                   }
            }
            DispatchQueue.main.async {
                self.tableview.reloadData()
            }
        } catch let error {
            print(error)
        }
    }
    task.resume()
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "articleCell", for: indexPath) as! articleCell        
    cell.title.text = self.groupedArticles[indexPath.section].articles?[indexPath.row].headline
    cell.desc.text = self.groupedArticles[indexPath.section].articles?[indexPath.row].desc
    cell.author.text = self.groupedArticles[indexPath.section].articles?[indexPath.row].author
    cell.date.text = self.groupedArticles[indexPath.section].articles?[indexPath.row].date

    cell.imgView.downloadImage(from: (self.groupedArticles[indexPath.section].articles?[indexPath.row].imageUrl!)!)
    return cell
}

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

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return groupedArticles[section].articles?.count ?? 0
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let webVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "web") as! WebviewViewController
    webVC.url = self.groupedArticles[indexPath.section].articles?[indexPath.row].url
    self.present(webVC, animated: true, completion: nil)
}

但是,出现错误:

self.groupedArticles.append(Issue(dateName: (articleFromJson["x_date"] 作为!字符串),文章:[文章(标题:(articleFromJson [“标题”] 作为! String), desc: (articleFromJson["excerpt"] as!String), 作者: (articleFromJson["x_author"] as!String),网址: (articleFromJson["x_featured_media"] as!String), imageUrl: (articleFromJson["x_featured_media"] as!String),日期: (articleFromJson["x_date"] as!String))]))

“无法将 '__NSDictionaryM' (0x106a35260) 类型的值转换为 'NSString' (0x1031d9c40)。”

这是正确的轨道吗?我该如何解决?


编辑 2

更新了 fetchArticles 函数:

func fetchArticles() {
    let urlRequest = URLRequest(url: URL(string: "X")!)
    let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
        if error != nil {
            print(error)
            return
        }
        do {
            let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? AnyObject
            if let articlesFromJson = json as? [[String : AnyObject]] {
                for articleFromJson in articlesFromJson {
                    // Get All Articles
                    var articleEntries = [Issue]()

                    articleEntries.append(Issue(dateName: (articleFromJson["x_date"] as! String), articles: [Article(headline: (articleFromJson["title"]?["rendered"] as! String), desc: (articleFromJson["excerpt"]?["rendered"] as! String), author: (articleFromJson["x_author"] as! String), url: (articleFromJson["x_featured_media"] as! String), imageUrl: (articleFromJson["x_featured_media"] as! String), date: (articleFromJson["x_date"] as! String))]))

                    // SORT Articles by KEY of X_Date(String)
                    var groupedArts = [String: [Issue]]()
                    var groupedKeys = Array<String>()

                    for article in articleEntries {
                        let index = (article.dateName?.startIndex)!..<(article.dateName?.endIndex)!
                        let keys = String(describing: article.dateName?[index])
                        if groupedArts[keys] != nil {
                            groupedArts[keys]?.append(article)
                            print("this array exists")
                        } else {
                            groupedArts[keys] = [article]
                            groupedKeys.append(keys)
                            print("this array does not exist")
                        }
                    }
                    print(groupedArts)
                    print(groupedKeys)
                }
            }
            DispatchQueue.main.async {
                self.tableview.reloadData()
            }
        } catch let error {
            print(error)
        }
    }
    task.resume()
}

根据我的理解,我应该解析条目,然后使用类似于示例代码的东西重新排序它们,但它会单独产生结果:

["可选(\"2016 年 2 月 14 日\")": [Journal.ViewController.Issue(dateName: Optional("February 14, 2016"), 文章:可选([Journal.ViewController.Article(标题: 可选(“案例文件:严重缺氧令人震惊”),描述: 可选(“ABC”),作者: 可选(“AUTHOR”),url:可选(“X”),imageUrl:可选(“X”),日期: 可选的("2016 年 2 月 14 日"))]))]] ["可选的(\"2 月 14 日, 2016\")"]

每篇文章都以此类推。我试图解析 IF 语句中的文章,但这会使一切崩溃。我能做什么?

【问题讨论】:

    标签: ios arrays json swift uitableview


    【解决方案1】:

    通常,您需要为您的数据源创建一个 Section 数组。

    struct Section {
         let date:Date
         var articles:[Article]
    }
    
    var groupedArticles = [Section]()
    

    当您将 JSON 解析为 Article 时,您应该将它们存储在此数组中。 Article 应该是一个结构,你应该查看https://github.com/Hearst-DD/ObjectMapperhttps://github.com/SwiftyJSON/SwiftyJSON

    那么你可以使用这些方法

    func numberOfSections(in tableView: UITableView) -> Int {
        return groupedArticles.count
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return groupedArticles[section].articles.count ?? 0
    }
    

    看到这个类似的答案 - https://stackoverflow.com/a/42277283/1189470

    【讨论】:

    • 感谢您的回复。我是超级新手,但我相信我实施了您建议的更改,但仍未产生正确的结果。请查看“编辑 1”。我走对了吗?
    • 你在正确的轨道上,但是你需要解析你的Articles,然后将它们解析成Sections。你不能只把append 变成groupedArticles。对于您创建的每篇文章,您需要查看是否应该将其添加到现有的Section,或者是否需要创建新的Section。然后您需要将所有这些部分添加到 groupedArticles 数组中。您看到的错误是“标题”和“摘录”都不是 JSON 中的字符串 - 它们是字典 - “渲染”:{值}。你应该看看我建议的 JSON 库,它们会让你的生活更轻松。
    • 请查看我的“编辑 2” - 我想我已按照您的指示进行操作,但仍然没有得到正确的结果。我使用了您的示例代码并尝试对其进行调整,这就是发生的情况 1)所有条目和索引都单独打印,因此它们似乎没有分组 2)IF 语句始终是“数组不存在”,我可以我一辈子都看不出来为什么。就 SwifyJson 而言 - 我已经查看并将其添加到我的项目中,但我真的是一个初学者 - 这看起来超级复杂.. 有没有办法在没有 SwifyJson 的情况下完成我需要做的事情?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多