[英]Decoding nested json array for ExpandableTableView in swift 4 and Xcode 9
I'm new to iOS and making an ExpandableTableView with JSON data. 我是iOS的新手,使用JSON数据制作了ExpandableTableView 。 The data is in form of nested arrays.
数据采用嵌套数组的形式。 I want to set data of parent array as TableView header and data of child array as ExpandableTable elements.
我想将父数组的数据设置为TableView标头,并将子数组的数据设置为ExpandableTable元素。 I'm performing JSONDecoding through struct and enums and storing the response in DataModelClass .
我正在通过struct和enums执行JSONDecoding并将响应存储在DataModelClass中 。 While Decoding it's throwing error
解码时会引发错误
typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))
that is ok because I know that I'm missing something very small. 可以,因为我知道我缺少了一些很小的东西。 I've gone through it many times but I'm unable to understand the problem.
我已经经历了很多次,但我无法理解问题。
There are many similar types of questions on stack but none of then are matching my criteria. 堆栈上有许多类似类型的问题,但没有一个符合我的标准。 Please help me out.
请帮帮我。
My JSON is 我的JSON是
[
{
"category_id": "1",
"category_name": "ROLL",
"category_start_time": "10:00:00",
"category_end_time": "22:59:59",
"data": [
{
"id": "301",
"item_code": null,
"item_name": "CHICKN ROLL",
"main_item_id": "1",
"item_price": null,
"tax_id": "0",
"tax_per": "0",
"tax_amount": "0",
"item_net_price": "180",
"sub_item_price": "0",
"sub_tax_amount": "0",
"sub_item_net_price": "0",
"created_date": "2018-02-28 12:20:53",
"created_by": null,
"image_name": "",
"image_path": null,
"quantity": null,
"notify_quant": null,
"active": "1",
"today_avilable": "1",
"kot": "1",
"counter_id": "0",
"store_id": "1"
}
]
}
]
and the Model class is 而Model类是
import Foundation
class AllStoreItems {
var category_id: String
var category_name: String
var category_start_time: String
var category_end_time: String
var data: [data]
var expanded: Bool
init(category_id: String, category_name: String, category_start_time: String, category_end_time: String, data: [data], expanded: Bool = false) {
self.category_id = category_id
self.category_name = category_name
self.category_start_time = category_start_time
self.category_end_time = category_end_time
self.data = data
self.expanded = expanded
}
}
class ItemsData {
var id: String
var item_code: String
var item_name: String
var main_item_id: String
var item_price: String
var tax_id: String
var tax_per: String
var tax_amount: String
var item_net_price: String
var sub_item_price: String
var sub_tax_amount: String
var sub_item_net_price: String
var created_date: String
var created_by: String
var image_name: String
var image_path: String
var quantity: String
var notify_quant: String
var active: String
var today_avilable: String
var kot: String
var counter_id: String
var store_id: String
init(id: String, item_code: String, item_name: String, main_item_id: String, item_price: String, tax_id: String, tax_per: String, tax_amount: String, item_net_price: String, sub_item_price: String, sub_tax_amount: String, sub_item_net_price: String, created_date: String, created_by: String, image_name: String, image_path: String, quantity: String, notify_quant: String, active: String, today_avilable: String, kot: String, counter_id: String, store_id: String) {
self.id = id
self.item_code = item_code
self.item_name = item_name
self.main_item_id = main_item_id
self.item_price = item_price
self.tax_id = tax_id
self.tax_per = tax_per
self.tax_amount = tax_amount
self.item_net_price = item_net_price
self.sub_item_price = sub_item_price
self.sub_tax_amount = sub_tax_amount
self.sub_item_net_price = sub_item_net_price
self.created_date = created_date
self.created_by = created_by
self.image_name = image_name
self.image_path = image_path
self.quantity = quantity
self.notify_quant = notify_quant
self.active = active
self.today_avilable = today_avilable
self.kot = kot
self.counter_id = counter_id
self.store_id = store_id
}
}
My struct and enums are 我的结构和枚举是
import Foundation
struct AllItem: Decodable {
var category_id: String
var category_name: String
var category_start_time: String
var category_end_time: String
var data: [data]
enum AllItem: String {
case category_id = "category_id"
case category_name = "category_name"
case category_start_time = "category_start_time"
case category_end_time = "category_end_time"
case data = "data"
}
}
struct data: Decodable {
var id: String
var item_code: String
var item_name: String
var main_item_id: String
var item_price: String
var tax_id: String
var tax_per: String
var tax_amount: String
var item_net_price: String
var sub_item_price: String
var sub_tax_amount: String
var sub_item_net_price: String
var created_date: String
var created_by: String
var image_name: String
var image_path: String
var quantity: String
var notify_quant: String
var active: String
var today_avilable: String
var kot: String
var counter_id: String
var store_id: String
enum data: String {
case id = "id"
case item_code = "item_code"
case item_name = "item_name"
case main_item_id = "main_item_id"
case item_price = "item_price"
case tax_id = "tax_id"
case tax_per = "tax_per"
case tax_amount = "tax_amount"
case item_net_price = "item_net_price"
case sub_item_price = "sub_item_price"
case sub_tax_amount = "sub_tax_amount"
case sub_item_net_price = "sub_item_net_price"
case created_date = "created_date"
case created_by = "created_by"
case image_name = "image_name"
case image_path = "image_path"
case quantity = "quantity"
case notify_quant = "notify_quant"
case active = "active"
case today_avilable = "today_avilable"
case kot = "kot"
case counter_id = "counter_id"
case store_id = "store_id"
}
}
and my ViewController is 而我的ViewController是
class CustomItemTableView: UITableViewCell {
@IBOutlet weak var textLabelOne: UILabel!
@IBOutlet weak var textLabelTwo: UILabel!
}
class AllItemsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, AllItemsHeaderViewDelegate {
@IBOutlet weak var headerStoreLogoIV: UIImageView!
@IBOutlet weak var tableView: UITableView!
var storeId: String = ""
var storeCatId: String = ""
var storeName: String = ""
var storeLogoLink: String = ""
@IBOutlet weak var storeImage: UIImageView!
@IBOutlet weak var storeNameLabel: UILabel!
let mainUrl = BaseURL()
var items = [AllStoreItems]()
var subItems = [ItemsData]()
override func viewDidLoad() {
super.viewDidLoad()
ExpandItemsApi()
let imgUrl: String = mainUrl.MainUrl + "logo/" + storeLogoLink
let imgUrlStr: String = imgUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
//let imgUrl2: URL = URL(string: imgUrlStr)!
//let imgUrl3 = URLRequest(url: imgUrl2!)
storeNameLabel.text = storeName
// storeNames.text = storeName
// storeCategory.text = storeCatId
// storeIds.text = storeId
// imgLink.text = storeLogoLink
storeImage.downloadedFrom(link: imgUrlStr)
}
@IBAction func backButton(_ sender: Any) {
self.dismiss(animated: false, completion: nil)
}
func ExpandItemsApi() {
let myActivityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
myActivityIndicator.center = view.center
myActivityIndicator.hidesWhenStopped = false
myActivityIndicator.startAnimating()
view.addSubview(myActivityIndicator)
let itemsUrl = URL(string: mainUrl.MainUrl + "viewmaincat")
var itemUrls = URLRequest(url: itemsUrl!)
itemUrls.httpMethod = "POST"
itemUrls.addValue("application/json", forHTTPHeaderField: "content-type")
itemUrls.addValue("application/json", forHTTPHeaderField: "Accept")
let storeDetails = ["store_id": storeId] as [String: String]
do {
itemUrls.httpBody = try JSONSerialization.data(withJSONObject: storeDetails, options: .prettyPrinted)
}catch let error {
toastNeck(message: "\(error)")
myActivityIndicator.stopAnimating()
myActivityIndicator.hidesWhenStopped = true
}
URLSession.shared.dataTask(with: itemUrls) {
(datas, response, error) in
if datas != nil {
do {
let itemDetails = try JSONDecoder().decode(AllItem.self, from: datas!)
self.items.append(AllStoreItems(category_id: itemDetails.category_id, category_name: itemDetails.category_name, category_start_time: itemDetails.category_start_time, category_end_time: itemDetails.category_end_time, data: itemDetails.data))
print(itemDetails.data)
// let subItem = try JSONDecoder().decode(data.self, from: datas!)
// self.subItems.append(ItemsData(id: subItem.id, item_code: subItem.item_code, item_name: subItem.item_name, main_item_id: subItem.main_item_id, item_price: subItem.item_price, tax_id: subItem.tax_id, tax_per: subItem.tax_per, tax_amount: subItem.tax_amount, item_net_price: subItem.item_net_price, sub_item_price: subItem.sub_item_price, sub_tax_amount: subItem.sub_tax_amount, sub_item_net_price: subItem.sub_item_net_price, created_date: subItem.created_date, created_by: subItem.created_by, image_name: subItem.image_name, image_path: subItem.image_path, quantity: subItem.quantity, notify_quant: subItem.notify_quant, active: subItem.active, today_avilable: subItem.today_avilable, kot: subItem.kot, counter_id: subItem.counter_id, store_id: subItem.store_id))
}catch let errors {
self.toastNeck(message: "\(errors)")
print(errors)
DispatchQueue.main.async{
myActivityIndicator.stopAnimating()
myActivityIndicator.hidesWhenStopped = true
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}.resume()
}
func numberOfSections(in tableView: UITableView) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items[section].data.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if items[indexPath.section].expanded {
return 50
}else {
return 0
}
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 5
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = AllItemsHeaderView()
header.customInit(title: items[section].category_name, section: section, delegate: self)
return header
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CustomItemTableView = tableView.dequeueReusableCell(withIdentifier: "customItems") as! CustomItemTableView
cell.textLabelOne.text = items[indexPath.section].data[indexPath.row].item_name
cell.textLabelTwo.text = items[indexPath.section].data[indexPath.row].item_price
return cell
}
func toggleSection(header: AllItemsHeaderView, section: Int) {
items[section].expanded = !items[section].expanded
tableView.beginUpdates()
for i in 0 ..< items[section].data.count {
tableView.reloadRows(at: [IndexPath(row: i, section: section)], with: .automatic)
}
tableView.endUpdates()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
toastNeck(message: items[indexPath.section].data[indexPath.row].item_name)
}
func toastNeck(message: String) {
DispatchQueue.main.async {
let toastLabel = UILabel(frame: CGRect(x: self.view.frame.size.width/2-100, y: self.view.frame.size.height/2, width: 200, height: 40))
toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.4)
toastLabel.textColor = UIColor.white
toastLabel.textAlignment = NSTextAlignment.center
toastLabel.text = message
toastLabel.layer.cornerRadius = 15
toastLabel.clipsToBounds = true
self.view.addSubview(toastLabel)
UIView.animate(withDuration: 8, animations: {
toastLabel.alpha = 0}, completion: {(isCompleted) in toastLabel.removeFromSuperview()})
}
}
}
if anyone need anything more, please comment... 如果还有其他需要,请发表评论...
Try changing these two lines: 尝试更改这两行:
let itemDetails = try JSONDecoder().decode(AllItem.self, from: datas!)
self.items.append(AllStoreItems(category_id: itemDetails.category_id, category_name: itemDetails.category_name, category_start_time: itemDetails.category_start_time, category_end_time: itemDetails.category_end_time, data: itemDetails.data))
to 至
let itemDetails = try JSONDecoder().decode([AllItem].self, from: datas!)
for item in itemDetails {
self.items.append(AllStoreItems(category_id: item.category_id, category_name: item.category_name, category_start_time: item.category_start_time, category_end_time: item.category_end_time, data: item.data))
}
And also there is no need of the enums AllItem
and data
as the property names are already same as JSON keys. 并且也不需要枚举
AllItem
和data
因为属性名称已经与JSON键相同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.