如何在 Swift 5 中使用 Alamofire 解析 json

Posted

技术标签:

【中文标题】如何在 Swift 5 中使用 Alamofire 解析 json【英文标题】:How to parse json with Alamofire in Swift 5 【发布时间】:2019-11-14 11:21:21 【问题描述】:

我是 ios 编程语言的新手,我正在尝试将数据从 WordPress JSON 提取到表格视图中。我遇到了错误:

'Any' 类型的值没有下标

当我尝试实例化数组的对象时。

这是 JSON:

[
 
    "id": 1352,
    "date": "2019-10-16T09:30:39",
    "date_gmt": "2019-10-16T09:30:39",
    "guid": 
        "rendered": "https://wepress.comm-it.it/ddjhgtr/"
    ,
    "modified": "2019-10-16T13:23:41",
    "modified_gmt": "2019-10-16T13:23:41",
    "slug": "ddjhgtr",
    "status": "publish",
    "type": "post",
    "link": "https://wepress.comm-it.it/ddjhgtr/",
    "title": "ddjhgtr",
    "content": "eryyreytyvggjggvhghhh",
    "excerpt": "eryyreyty",
    "author": 2,
    "featured_media": 
        "id": 1418,
        "url": "https://wepress.comm-it.it/wp-content/uploads/2019/10/10-62.jpeg"
    ,
    "comment_status": "open",
    "ping_status": "open",
    "sticky": false,
    "template": "",
    "format": "standard",
    "meta": [],
    "categories": [
        
            "id": 1,
            "name": "Uncategorized",
            "description": ""
        
    ],
    "tags": [],
    "_links": 
        "self": [
            
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/posts/1352"
            
        ],
        "collection": [
            
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/posts"
            
        ],
        "about": [
            
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/types/post"
            
        ],
        "author": [
            
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/users/2"
            
        ],
        "replies": [
            
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/comments?post=1352"
            
        ],
        "version-history": [
            
                "count": 3,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/posts/1352/revisions"
            
        ],
        "predecessor-version": [
            
                "id": 1419,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/posts/1352/revisions/1419"
            
        ],
        "wp:featuredmedia": [
            
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/media/1418"
            
        ],
        "wp:attachment": [
            
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/media?parent=1352"
            
        ],
        "wp:term": [
            
                "taxonomy": "category",
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/categories?post=1352"
            ,
            
                "taxonomy": "post_tag",
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/tags?post=1352"
            ,
            
                "taxonomy": "difficulty-level-course",
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/difficulty-level-course?post=1352"
            ,
            
                "taxonomy": "category-course",
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/category-course?post=1352"
            ,
            
                "taxonomy": "location-course",
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/location-course?post=1352"
            ,
            
                "taxonomy": "duration-course",
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/duration-course?post=1352"
            
        ],
        "curies": [
            
                "name": "wp",
                "href": "https://api.w.org/rel",
                "templated": true
            
        ]
    
 ,

....(许多其他新闻对象)


    "id": 774,
    "date": "2019-10-07T07:30:51",
    "date_gmt": "2019-10-07T07:30:51",
    "guid": 
        "rendered": "https://wepress.comm-it.it/name-here/"
    ,
    "modified": "2019-10-07T07:30:51",
    "modified_gmt": "2019-10-07T07:30:51",
    "slug": "name-here",
    "status": "publish",
    "type": "post",
    "link": "https://wepress.comm-it.it/name-here/",
    "title": "name here",
    "content": "desc here",
    "excerpt": "desc here",
    "author": 2,
    "featured_media": null,
    "comment_status": "open",
    "ping_status": "open",
    "sticky": false,
    "template": "",
    "format": "standard",
    "meta": [],
    "categories": [
        
            "id": 1,
            "name": "Uncategorized",
            "description": ""
        
    ],
    "tags": [],
    "_links": 
        "self": [
            
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/posts/774"
            
        ],
        "collection": [
            
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/posts"
            
        ],
        "about": [
            
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/types/post"
            
        ],
        "author": [
            
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/users/2"
            
        ],
        "replies": [
            
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/comments?post=774"
            
        ],
        "version-history": [
            
                "count": 0,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/posts/774/revisions"
            
        ],
        "wp:attachment": [
            
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/media?parent=774"
            
        ],
        "wp:term": [
            
                "taxonomy": "category",
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/categories?post=774"
            ,
            
                "taxonomy": "post_tag",
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/tags?post=774"
            ,
            
                "taxonomy": "difficulty-level-course",
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/difficulty-level-course?post=774"
            ,
            
                "taxonomy": "category-course",
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/category-course?post=774"
            ,
            
                "taxonomy": "location-course",
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/location-course?post=774"
            ,
            
                "taxonomy": "duration-course",
                "embeddable": true,
                "href": "https://wepress.comm-it.it/wp-json/wp/v2/duration-course?post=774"
            
        ],
        "curies": [
            
                "name": "wp",
                "href": "https://api.w.org/rel",
                "templated": true
            
        ]
      
  
]

目前我有兴趣获取这些“对象”的图像 (featured_media)、标题和内容,并将它们放入 tableView。事实上,这里是我为他们创建的结构:

新闻表示包含在 JSON 数组中的结构

struct News 
    public var id: Int
    public var title: String
    public var content: String
    public var image: FeaturedMedia

struct FeaturedMedia 
    public var id: Int
    public var url: String

这是UITableViewCell 类:

import UIKit

class NewsTableViewCell: UITableViewCell 
    @IBOutlet weak var newsImage: UIImageView!
    @IBOutlet weak var newsTitle: UILabel!
    @IBOutlet weak var newsContent: UILabel!

    override func awakeFromNib() 
        super.awakeFromNib()
    

    override func setSelected(_ selected: Bool, animated: Bool) 
        super.setSelected(selected, animated: animated)
    

这里是UITableViewController 类:

import UIKit
import Alamofire
import Alamofire_SwiftyJSON
import SwiftyJSON

class NewsTableViewController: UITableViewController 

    var newsList: [News] = [News]()

    func parseJsonNews() 
        DispatchQueue.main.async 
            Alamofire.request("link request", method: .get).responseJSON  (response) in
                switch response.result 
                case .success(let value):
                    let news = [value]
                    print(news) // here in console it prints correctly the json, starting with [<__NSArrayI 0x6000001a9e60 ....
                    for new in news 
                        let title = new["title"]
                        print(title)
                    
                    print(newsss)

                    self.tableView.reloadData()
                case.failure(let error):
                    print(error.localizedDescription)
                
            )
        
    

    override func viewDidLoad() 
        super.viewDidLoad()
        parseJsonNews()
    

    // MARK: - Table view data source

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

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return self.newsList.count
    


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "newsCell", for: indexPath) as? NewsTableViewCell


        // Configure the cell...
        let imageUrl = URL.init(string: newsList[indexPath.row].featuredMedia.url)
        cell?.newsTitle.text = self.newsList[indexPath.row].title
        cell?.newsContent.text = self.newsList[indexPath.row].content
        cell.newsImage.load(url: imageUrl!)
        return cell!
    


extension UIImageView 
    func load(url: URL) 
        DispatchQueue.global().async  [weak self] in
            if let data = try? Data(contentsOf: url) 
                if let image = UIImage(data: data) 
                    DispatchQueue.main.async 
                        self?.image = image
                    
                
            
        
    

寻找解决方案,我刚刚找到了许多解析字典 JSON 的方法,但在这种情况下,它是一个数组,所以我修改了您在 parseJsonNews 方法处阅读的代码,但它不能正常工作。

如果有任何帮助,将不胜感激。

【问题讨论】:

也许这对你有用 -> medium.com/better-programming/json-parsing-in-swift-2498099b78f 这一行打印什么? print(title) 你到底在哪一行得到错误? 您需要使用 JsonDecoder 来解析响应中的值。您采用的结构应该是可编码的,然后您可以使用 JSONDecoder 将它们解码到您的模型类中。如果您需要有关 JSONDecoder 代码的帮助,请告诉我。 @FaysalAhmed 不,它不打印任何东西 【参考方案1】:

您可以像这样使用Codable 进行解码:

let data = try? JSONDecoder().decode([DummyData].self, from: jsonData)

但首先,您的所有模型都必须符合Codable 协议。例如:

struct DummyData: Codable 
    let id: Int
    let date, dateGmt: String
    let modified, modifiedGmt, slug, status: String
    let type: String
    let link: String
    let title, content, excerpt: String
    let author: Int
    let commentStatus, pingStatus: String
    let sticky: Bool
    let template, format: String

    enum CodingKeys: String, CodingKey 
        case id, date
        case dateGmt = "date_gmt"
        case modified
        case modifiedGmt = "modified_gmt"
        case slug, status, type, link, title, content, excerpt, author
        case commentStatus = "comment_status"
        case pingStatus = "ping_status"
        case sticky, template, format
    

【讨论】:

现在开始工作了!但是当我启动模拟器时,它正确设置了表格视图,但是当我滚动 tableView 时,行的高度会变大 这听起来像自动布局问题。我无能为力,因为我不知道细节,但 Apple 有一个关于 Auto Layout 的非常好的文档。 developer.apple.com/library/archive/documentation/… 您还可以在UITableViewDelegateheightForRowAt 函数中更改所有单元格的高度。 developer.apple.com/documentation/uikit/uitableviewdelegate/…【参考方案2】:

有几点:

    错误value of type 'Any' has no subscripts,指的是你的行let title = new["title"].success枚举中Alamofire的响应结果返回Any的类型, 这适用于您获取的整个数据数组。 swift 中的Any 类型没有任何subscripts 实现(即:您不能使用以下语法obj['MY_VAR_NAME'] 访问其中的变量。

    为了像let title = new["title"] 这样从news 对象访问title,您必须首先将对象转换为字典,可以这样完成:

            // ... 
            let news = [value]
            print(news)
            for new in news 
                if let obj = new as? [String: Any] 
                    let title = obj["title"]
                    print(title)
                
            
            // ...
    

    为了解析/使用您的自定义结构,它们必须首先遵守 swift 的Codable 协议。

     /// Example show only News, but the same which be used for FeaturedMedia
      struct News 
        public var id: Int
        public var title: String
        public var content: String
        public var image: FeaturedMedia?
        init?(jsonString: String) 
           guard let data = jsonString.data(using: .utf8) else 
                 return nil
           
           guard let object = News(data: data) else 
                    return nil
           
           self = object
       
    
       init?(data: Data) 
           guard let object = try? JSONDecoder().decode(News.self, from:  
            data) else 
                  return nil
           
          self = object
      
      // Optional, for custom key names (i.e: "image" instead of "featured_media"
      private enum CodingKeys: String, CodingKey 
             case id = "id"
             case image = "featured_media"
           // etc..
      
    
    
    

完成第 4 步后,您可以像这样初始化对象:

            // ... 
            let news = [value]
            print(news)
            for new in news 
                if let obj = News(new) 
                  /// obj is now a News object
                    let title = obj.title
                    print(title)
                
            
            // ...

如果您正在寻求更多信息(例如初始化整个数组) 退房this 我希望我已经把事情弄清楚了:)

【讨论】:

【参考方案3】:
 func ComplainData() 
     let semaphore = DispatchSemaphore(value: 0)
     var request = URLRequest(url: URL(string: Constant.localBaseurl2 + "compID") !, timeoutInterval: Double.infinity)
     request.httpMethod = "GET"
     let task = URLSession.shared.dataTask(with: request) 
         data,
         response,
         error in
         if let response = response 
             let nsHTTPResponse = response as!HTTPURLResponse
             print(nsHTTPResponse)
         

         if let error = error 
             print("\(error)")
             return
         

         if let data = data 
             DispatchQueue.main.async 
                 let decoder = JSONDecoder()
                 decoder.keyDecodingStrategy = .convertFromSnakeCase //or any other Decoder\

                 do 
                     let jsonDecoder = JSONDecoder()
                     let memberRecord =
                         try jsonDecoder.decode(COMPLAINTSVC.GetComplaints.self, from: data)
                     print(memberRecord.message)

                     for detailData in memberRecord.message 
                         print(detailData)
                     
                  catch 
                     print(error.localizedDescription)
                 
             
         
         semaphore.signal()
     
     task.resume()
     semaphore.wait()
 

【讨论】:

您应该为答案添加解释。 How to parse json with Alamofire 你的回答中没有使用 Alamofire,这是题外话。

以上是关于如何在 Swift 5 中使用 Alamofire 解析 json的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Alamofire 5.0.0-beta.3 (Swift 5) 上传图片(多部分)

如何在 swift 5 中使用 alamofire 对登录到我的 iOS 应用程序的用户进行身份验证?

如何在 Alamofire 中上传文件并在参数中传递数据 - swift 5

如何在 swift5 和 Alamofire 5 beta 版本中获取和保存响应?

使用 PHP 在 Swift 5 中使用 Alamofire 接收图像上传

在 Swift 中使用 Alamofire 5.0 获取 3 级深度 JSON 值