简体   繁体   中英

How to append values from a JSON to an array?

I'm trying to get values from a JSON and append them to titleArray .

func updateUI() {
        DispatchQueue.global(qos: .background).async {
            // network call to the API
            self.fetchTipsJson(completion: { (res) in
                switch res {
                case .success(let tips):
                     self.titleArray.append(tips.responseList!.values[title]) // Cannot subscript a value of type '[Value]' with an index of type 'String?'
                    print(self.titleArray)

                case .failure(let err):
                    print("Failed to fetch tips:", err)
                }

            })
            DispatchQueue.main.async {
                // Update the UI Label here

            }
        }
    }

I get an error but I don't think this is how it's supposed to be done.

The JSON:

{
    "$type": "DTOMapper.DTOResponseList`1[[Telemed.Dto.DTOTip, Telemed.Dto]], DTOMapper",
    "ResponseList": {
        "$type": "System.Collections.Generic.List`1[[Telemed.Dto.DTOTip, Telemed.Dto]], mscorlib",
        "$values": [
            {
                "$type": "Telemed.Dto.DTOTip, Telemed.Dto",
                "Title": "NO TE JUNTES CON LUQUITAS",
                "Text": "Porque si tenes un amigo lucas y otro amigo lucas, tenés dos lucas. Pero no te sirven para pagar nada",
                "GroupName": "TGC.Tips1",
                "ConfigurationPath": "TelemedGlobalConfig>Tips>Tips[0]"
            },
            {
                "$type": "Telemed.Dto.DTOTip, Telemed.Dto",
                "Title": "no te emborraches en las fiestas",
                "Text": "Terminarás pateando globos",
                "GroupName": "TGC.Tips2",
                "ConfigurationPath": "TelemedGlobalConfig>Tips>Tips[1]"
            }
        ]
    },
    "StatusCode": 200,
    "ErrorId": 0
}

Am I accessing the $values correctly? If it helps, titleArray will be used with an UILabel.

Edit for updateLabels() :

func updateLabels() {
        self.myTimer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { (t) in
            self.titleLabel.text = self.titleArray[self.counter] as? String
            self.textLabel.text = self.textArray[self.counter] as? String
            self.counter += 1
            if self.counter == self.titleArray.count && self.counter == self.textArray.count{
                t.invalidate()
            }
        }
    }

Edit for callback:

do {
            let tips = try JSONDecoder().decode(Root.self, from: data!)
            self.titleArray = tips.responseList!.values.map { $0.title }
            self.textArray = tips.responseList!.values.map { $0.text }
            DispatchQueue.main.async {
                self.updateLabels()
            }
            completion(.success(tips))
        } catch let jsonError {
            completion(.failure(jsonError))
        }

Edit for viewDidLoad() :

override func viewDidLoad() {
        super.viewDidLoad()

        fetchTipsJson { (res) in
            switch res {
            case .success:
                return
            case .failure(let err):
                print("Failed to fetch tips:", err)
            }
        }
    }

values is an array not a dictionary , you need to map it to the title string , so try

let str = """

{
"$type": "DTOMapper.DTOResponseList`1[[Telemed.Dto.DTOTip, Telemed.Dto]], DTOMapper",
"ResponseList": {
"$type": "System.Collections.Generic.List`1[[Telemed.Dto.DTOTip, Telemed.Dto]], mscorlib",
"$values": [
{
"$type": "Telemed.Dto.DTOTip, Telemed.Dto",
"Title": "NO TE JUNTES CON LUQUITAS",
"Text": "Porque si tenes un amigo lucas y otro amigo lucas, tenés dos lucas. Pero no te sirven para pagar nada",
"GroupName": "TGC.Tips1",
"ConfigurationPath": "TelemedGlobalConfig>Tips>Tips[0]"
},
{
"$type": "Telemed.Dto.DTOTip, Telemed.Dto",
"Title": "no te emborraches en las fiestas",
"Text": "Terminarás pateando globos",
"GroupName": "TGC.Tips2",
"ConfigurationPath": "TelemedGlobalConfig>Tips>Tips[1]"
}
]
},
"StatusCode": 200,
"ErrorId": 0
}
"""



do {
      let res = try JSONDecoder().decode(Root.self, from: Data(str.utf8))
      let arr = res.responseList.values.map { $0.title }
      print(arr)
   }
   catch {
        print(error)
    }
}

// MARK: - Empty
struct Root: Codable {
    let type: String
    let responseList: ResponseList
    let statusCode, errorID: Int

    enum CodingKeys: String, CodingKey {
        case type = "$type"
        case responseList = "ResponseList"
        case statusCode = "StatusCode"
        case errorID = "ErrorId"
    }
}

// MARK: - ResponseList
struct ResponseList: Codable {
    let type: String
    let values: [Value]

    enum CodingKeys: String, CodingKey {
        case type = "$type"
        case values = "$values"
    }
}

// MARK: - Value
struct Value: Codable {
    let type, title, text, groupName: String
    let configurationPath: String

    enum CodingKeys: String, CodingKey {
        case type = "$type"
        case title = "Title"
        case text = "Text"
        case groupName = "GroupName"
        case configurationPath = "ConfigurationPath"
    }
}

Edit:

var counter = 0

var myTimer:Timer!

self.myTimer =    Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { (t) in
    self.lbl.text = self.titleArr[self.counter]
    counter += 1
    if self.counter == self.titleArr.count {
        t.invalidate()
    }
}

First thing tips.responseList!.values is an Array not Dictionary . So you can't do like

self.titleArray.append(tips.responseList!.values[title])

You can do it by iterating all element inside the array.

self.titleArray.append(contentsOf:tips.responseList!.values.compactMap { $0.title })

Please ignore the syntax error because it is a just idea.

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