简体   繁体   中英

How to parse json with Alamofire in Swift 5

I'm new in iOS programming language and I'm trying to fetch data from a WordPress JSON into a table view. I'm encountering the error:

value of type 'Any' has no subscripts

when I try to instantiate the object of the array.

Here is the 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
            }
        ]
    }
 },

....(many other News objects)

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

For the moment I'm interested to get just the image ( featured_media ), title and content of these "objects" and put them into the tableView . Indeed here are the structs that I created for them:

The news represents the struct contained into the JSON array

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
}

Here is the UITableViewCell class:

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

And here the UITableViewController class:

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

Looking for a solution, I just found many ways to parse dictionary JSON, but in this case, it is an array so I modified the code as you read at parseJsonNews method but it doesn't work properly.

Would be grateful for any help.

You can decode with Codable like this:

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

But first, all of your models must comform Codable protocol. For example:

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

A couple of things:

  1. The error value of type 'Any' has no subscripts , refers to your line let title = new["title"] . the response results from Alamofire in the .success enum returns a type of Any , this is true to the whole array of data that you fetched. The Any type in swift doesn't have any subscripts implementations (ie: you cannot access vars inside it using the following syntax obj['MY_VAR_NAME'] .

  2. In order to access the title from your news object like so let title = new["title"] , you have to first cast the objects to a dictionary, this could be done like this:

     //... let news = [value] print(news) for new in news { if let obj = new as? [String: Any] { let title = obj["title"] print(title) } } //...
  3. In order to parse/use your custom structs, they must first comply to swift's Codable protocol.

     /// 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 (ie: "image" instead of "featured_media" private enum CodingKeys: String, CodingKey { case id = "id" case image = "featured_media" // etc.. } }

After you've done number 4, you can then init your objects like so:

            // ... 
            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)
                }
            }
            // ...

if you are in pursuit for even more info (for example to init the whole array) check out this I hope I've cleared things up:)

 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()
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM