此API响应:
{
"status": 200,
"message": "Success",
"data": {
"result": [
{
"name": "Anything",
"response": [
{
"name": "XYZ",
"prize": "1.86"
},
{
"name": "ABCD",
"prize": "9.86"
}
]
}
],
"overall": "XYZ"
}
}
我如何才能在响应中汇总奖品,因为我必须在表的标题中显示奖品。我做到了。
var prizeArr = [Int]()
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: cellReuseIdentifier) as! OverallHeaderCell
let countArr = winnerArr![section]["response"] as? Array<Dictionary<String,Any>>
prizeArr = (countArr!.compactMap{ $0["prize"] })
print(prizeArr)
header.textL[0].text = winnerArr![section]["name"] as? String
header.textL[3].text = "\(String(describing: countArr!.count))"
return header
}
我试图将prize
存储在prizeArr
中,然后将其汇总。但是,它显示nil,但是当我在终端中将其写入时,它将分别给出值。我怎样才能将这个ArrayObject中的奖金相加?
此外,当我使用prizeArr = [String]()
时,它可以工作并将奖品存储在数组中,但是对于Int
,为什么它不起作用?
答案 0 :(得分:1)
首先,正如@Benhamine指出的那样,您应该从一个干净的体系结构开始,并将JSON映射到类型安全的类中。
让我们定义一个表示我们的JSON的结构,以便我们可以更好地在我们的App中使用它。 JSON是我们从不希望通过我们的应用程序传递的东西。我们宁愿绕过一些定义明确并记录在案的内容,因此我们无需进行任何强行拆解和崩溃应用程序。
struct JSONResponse: Codable {
enum CodingKeys: String, CodingKey {
case data
}
let data: Data
}
extension JSONResponse {
struct Data: Codable {
enum CodingKeys: String, CodingKey {
case results = "result"
}
let results: [Result]
}
}
extension JSONResponse.Data {
struct Result: Codable {
let name: String
let winners: [Winner]
enum CodingKeys: String, CodingKey {
case winners = "response"
case name
}
}
}
extension JSONResponse.Data.Result {
struct Winner: Codable {
let name: String
let prize: String
}
}
使用Codable进行解析非常简单。下面的代码将显示我们如何将其转换为JSON,以及如何获取浮点值的总和。
do {
let o: JSONResponse = try JSONDecoder().decode(JSONResponse.self, from: jsonData)
let floatValues = o.data.results.flatMap({ $0.winners }).compactMap({ Float($0.prize) })
floatValues.reduce(0, +)
print(floatValues)
} catch let e {
print(e)
}
我们现在有了获取此信息所需的构造块,因此让我们从想要的代码开始,将其与您的代码联系起来。
/// We store our main data type for easy reference
var resultsBySection: [Result]
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: cellReuseIdentifier) as! OverallHeaderCell
let currentResults = resultsBySection[section]
let prizeTotals = currentResults.flatMap({ $0.winners }).compactMap({ Float($0.prize) })
let totalPriceMoney = prizeTotals.reduce(0, +)
header.textL[0].text = currentResults.name
header.textL[3].text = "\(String(describing: totalPriceMoney))"
return header
}
请注意,在上面的代码中我如何不在单元出队中进行任何JSON解码。理想情况下,应该在我们检索JSON并将其转换为我们的类型时完成。
任何代码经验中的重要部分都应该对我们编写的代码有所反思,并考虑如何对其进行重构。
在上面的示例中,我们可能会将总数硬编码到控制器上,或者创建一个自定义数据结构,当我们解析JSON时将为我们执行此操作。如果我们总是需要总计,我们是否总是要手动计算总计?我们可以有一个自定义函数来进行计算,也可以只在JSON解码逻辑中进行。
无论如何,我们的想法是我们应该始终看待正在写的东西,并质疑如何改进
答案 1 :(得分:0)
let sum = winnerArr?[section]["response"].reduce(0, { x, y in
x + y["prize"]
}) ?? 0
顺便说一句,我建议解析响应并将其变成可用的对象,而不是处理原始响应:https://developer.apple.com/swift/blog/?id=37
答案 2 :(得分:0)
尝试使用此Codable
解决方案来共同减少奖品:
struct Winners: Codable {
let status: Int
let message: String
let data: DataClass
}
struct DataClass: Codable {
let result: [Result]
let overall: String
}
struct Result: Codable {
let name: String
let response: [Response]
}
class Response: Codable {
let name: String
let prize: Double
init(name: String, prize: Double) {
self.name = name
self.prize = prize
}
enum CodingKeys: String, CodingKey {
case name
case prize
}
enum SerializationError: Error {
case missing(String)
case invalid(String, Any)
}
public required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
let prizeString = try container.decode(String.self, forKey: .prize)
guard let prize = Double(prizeString) else {
throw SerializationError.invalid("prize", prizeString)
}
self.prize = prize
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode("\(prize)", forKey: .prize)
}
}
func testing() {
let winners = try! JSONDecoder().decode(Winners.self, from: jsonData)
let sum = winners.data.result[section].response
.map({ $0.prize })
.reduce(0, +)
print(sum)
}
答案 3 :(得分:0)
感谢你们所有人的帮助。我是新手,不熟悉Codable。感谢您向我介绍相同的内容。我将尝试理解它,并将其用于将来的目的。
所以,回到答案:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
self.prizeArr.removeAll()
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: cellReuseIdentifier) as! OverallHeaderCell
let resArr = self.winnerArr![section]["response"]! as? Array<Dictionary<String,Any>>
for prize in resArr!
{
let doubleStr = prize["prize"] as? NSString
self.prizeArr.append((doubleStr?.doubleValue)!)
}
let sumedArr = prizeArr.reduce(0, +)
let countArr = winnerArr![section]["response"] as? Array<Dictionary<String,Any>>
header.textL[0].text = winnerArr![section]["name"] as? String
header.textL[1].text = "$\(sumedArr)"
header.textL[3].text = "\(String(describing: countArr!.count))"
return header
}
在这里,我将每个字符串转换为双精度字符串并将其附加到prizeArr
,然后,最后,对整个数组求和以得到所需的结果。但是,这不是理想的方法。该答案适用于像我这样的所有新手,请学习Codables
。