【问题标题】:How to parse json with Alamofire in Swift 5如何在 Swift 5 中使用 Alamofire 解析 json
【发布时间】: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 方法处阅读的代码,但它不能正常工作。

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

【问题讨论】:

  • 这一行打印什么? print(title)
  • 你到底在哪一行得到错误?
  • 您需要使用 JsonDecoder 来解析响应中的值。您采用的结构应该是可编码的,然后您可以使用 JSONDecoder 将它们解码到您的模型类中。如果您需要有关 JSONDecoder 代码的帮助,请告诉我。
  • @FaysalAhmed 不,它不打印任何东西

标签: ios json swift xcode


【解决方案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
    }
}

【讨论】:

【解决方案2】:

有几点:

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

  2. 为了像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)
                }
            }
            // ...
    
  3. 为了解析/使用您的自定义结构,它们必须首先遵守 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,这是题外话。
    猜你喜欢
    • 2020-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-05
    • 1970-01-01
    • 2019-05-12
    • 2020-11-19
    • 1970-01-01
    相关资源
    最近更新 更多