我是 iOS 的新手,并使用 JSON 数据制作 ExpandableTableView 。数据采用嵌套数组的形式。我想将父数组的数据设置为 TableView标题,将子数组的数据设置为ExpandableTable元素。我通过结构和枚举执行 JSON解码,并将响应存储在 DataModelClass 中。 在解码它时抛出错误
typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))
没关系,因为我知道我错过了很小的东西。我经历了很多次,但我无法理解这个问题。
堆栈上有许多相似类型的问题,但没有一个符合我的标准。请帮帮我。
我的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"
}
]
}
]
,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
}
}
我的结构和枚举是
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"
}
}
我的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()})
}
}
}
如果有人需要更多,请发表评论......
答案 0 :(得分:1)
尝试更改这两行:
<mat-tab label="Active">
<mat-icon for="search">search</mat-icon>
<input type="search" [(ngModel)]="filter" name="search" class="search" placeholder="Company">
<ul>
<li *ngFor="let message of activeMessages| messagefilter: filter" (click)="showMessage(message)" [class.activeShow]="message.id == message_id">
<span>{{message.messages[message.messages.length -1].updated_at | date:'dd.MM.yyyy'}}</span>
<img style="width: 40px;" [src]="message.from_user_image || '../assets/images/msg.png'"/>
<p style="padding-top: 16px;display: inline;">{{message.from_user_name}}</p>
<p style="padding-top: 10px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;"><b>{{message.messages[message.messages.length -1].text}}</b></p>
</li>
</ul>
</mat-tab>
到
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))
此外,不需要枚举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))
}
和AllItem
,因为属性名称已与JSON键相同。