如何使用 Alamofire 和 SwiftyJSON 将 JSON 字典元素中的所有元素附加到数组

How to append all elements from an element of JSON dictionary to an array with Alamofire and SwiftyJSON

我正在尝试追加给定 JSON 字典中可用的从最新到最旧的所有收盘价。我正在使用的 URL 请求如下:

https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=AMZN&interval=60min&outputsize=full&apikey=5H2L6THH6BSCAMKO

如您所见,结果是一个按最近日期排序的字典,在该字典中,有各种选项,包括收盘价。可以在下面看到它的一点点。

{
"Meta Data": {
    "1. Information": "Intraday (60min) open, high, low, close prices and volume",
    "2. Symbol": "AMZN",
    "3. Last Refreshed": "2018-08-15 12:30:00",
    "4. Interval": "60min",
    "5. Output Size": "Full size",
    "6. Time Zone": "US/Eastern"
},
"Time Series (60min)": {
    "2018-08-15 12:30:00": {
        "1. open": "1892.1620",
        "2. high": "1898.0000",
        "3. low": "1879.3600",
        "4. close": "1892.5000",
        "5. volume": "893752"
    },
    "2018-08-15 11:30:00": {
        "1. open": "1873.4399",
        "2. high": "1893.3500",
        "3. low": "1873.4399",
        "4. close": "1892.1200",
        "5. volume": "798959"
    },
    "2018-08-15 10:30:00": {
        "1. open": "1905.1899",
        "2. high": "1915.5300",
        "3. low": "1871.0200",
        "4. close": "1871.0200",
        "5. volume": "1614045"
    },

现在,我想按顺序从最近的日期开始追加收盘价。我尝试使用 for 循环、while 循环并使用 Date 结构来以有序的方式成功请求每个日期的收盘价,但是当我尝试访问以前的日期时它会卡住。我正在使用的功能是以下一个。

    func get1HPriceArr(stock:String, dataPoints:Int){


    let url = "https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=\(stock)&interval=60min&outputsize=full&apikey=5H2L6THH6BSCAMKO"


    Alamofire.request(url, method: .get).validate().responseJSON { response in
        switch response.result  {
        case .success(let value):



            let timeZone = TimeZone(secondsFromGMT: 0000)

            let dateFormatter = DateFormatter()

            dateFormatter.timeZone = timeZone!


            dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

            let json = JSON(value)

            var DatesArray:[String] = []

            var ClosingPrices:[Double] = []

            var followingDate:String?

            func AddDates() -> [Double]{

                print("FollowingDate just below the func  is \(followingDate)")

                while ClosingPrices.count != dataPoints {


                    print("Following date in the while loop is \(followingDate)")


                    let mostRecentRefreshed = json["Meta Data"]["3. Last Refreshed"].stringValue

                    print("Most recent refreshed is \(mostRecentRefreshed)")

                    if followingDate == nil {

                        followingDate = mostRecentRefreshed

                        let closingPrice = json["Time Series (60min)"][followingDate!]["4. close"].doubleValue

                        print("Following Date was nil and now its value is \(followingDate!)")
                        DatesArray.append(followingDate!)
                        ClosingPrices.append(closingPrice)

                        print(ClosingPrices)


                        // You must check if most recent refreshed is 16:00

                        let followingDateDate = dateFormatter.date(from: followingDate!)

                        let hour = Calendar.current.component(.hour, from: followingDateDate!)

                        let minutes = Calendar.current.component(.minute, from: followingDateDate!)

                        if hour == 16{


                            let halfNHourMore = Calendar.current.date(byAdding: .minute,value: 30, to: followingDateDate!)

                            let dateStringNil = dateFormatter.string(from: halfNHourMore!)

                            followingDate = dateStringNil


                        } else {

                            print("Last refreshed time is not 16:00, so following date was nil and now is \(followingDate)")

                        }

                    }

                    print("Following date is \(String(describing: followingDate))")

                    var currentDate = dateFormatter.date(from: followingDate!)

                    print("Current Date is \(currentDate)")

                    let dateHour = Calendar.current.component(.hour, from: currentDate!)

                    let dateMinutes = Calendar.current.component(.minute, from: currentDate!)

                    var oneHourLess:Date!

                    if dateHour == 16 && dateMinutes == 0 {

                        oneHourLess = Calendar.current.date(byAdding: .minute,value: -30, to: currentDate!)

                    } else {

                        oneHourLess = Calendar.current.date(byAdding: .hour,value: -1, to: currentDate!)

                    }



                    let dateString = dateFormatter.string(from: oneHourLess!)

                    if (dateString.contains("17:30:00")) || (dateString.contains("18:30:00")) || (dateString.contains("19:30:00")) || (dateString.contains("20:30:00")) || (dateString.contains("21:30:00")) || (dateString.contains("22:30:00")) || (dateString.contains("23:30:00")) || (dateString.contains("00:30:00")) || (dateString.contains("01:30:00")) || (dateString.contains("02:30:00")) || (dateString.contains("03:30:00")) || (dateString.contains("04:30:00")) || (dateString.contains("05:30:00")) || dateString.contains("06:30:00") || dateString.contains("05:30:)0") || dateString.contains("06:30:00") || dateString.contains("07:30:00") || dateString.contains("08:30:00") || dateString.contains("09:30:00") {

                        print("OneHourLess is \(oneHourLess)")

                        print("Its closing time since the time is \(dateString)")

                    } else {


                        DatesArray.append(dateString)

                        followingDate = dateString

                        print("Following date is \(String(describing: followingDate))")

                        currentDate = dateFormatter.date(from: followingDate!)

                        let closingPrice = json["Time Series (60min)"][followingDate!]["4. close"].doubleValue

                        let weekday = Calendar.current.component(.weekday, from: currentDate!)

                        let hour = Calendar.current.component(.hour, from: currentDate!)

                        let minutes = Calendar.current.component(.minute, from: currentDate!)

                        print("Weekday is \(weekday)")

                        print("Hour is \(hour)h")

                        print("Minutes are \(minutes)min")

                        ClosingPrices.append(closingPrice)
                        print("Closing prices count is \(ClosingPrices.count)")
                        print("Closing prices array is \(ClosingPrices)")



                        let oneDayLess = Calendar.current.date(byAdding: .day,value: -1, to: currentDate!)
                        let oneDayLessString = dateFormatter.string(from: oneDayLess!)
                        followingDate = oneDayLessString

                        print("Following date minus one day is \(followingDate)")




                    }












                }

                print(DatesArray)
                print("Closing prices are \(ClosingPrices)")

                return ClosingPrices


            }

            AddDates()


        case .failure(let error):
            print(error)
        }

    }

} // End of get1HPriceArr()

有什么方法可以追加数组中的所有元素(按照 api 给出的相同顺序)而不必自己以编程方式传递日期?或者有什么其他方法可以达到相同的结果吗?

这是 Decodable 的独立建议。它比 SwiftyJSON 更通用。您可以在 Playground 中对其进行测试。

result 是结构 Price 的数组,按 date 降序排列。最好使用数组,因为字典是无序的。

JSON

let jsonString = """
{
"Meta Data": {
"1. Information": "Intraday (60min) open, high, low, close prices and volume",
"2. Symbol": "AMZN",
"3. Last Refreshed": "2018-08-15 12:30:00",
"4. Interval": "60min",
"5. Output Size": "Full size",
"6. Time Zone": "US/Eastern"
},
"Time Series (60min)": {
    "2018-08-15 12:30:00": {
    "1. open": "1892.1620",
    "2. high": "1898.0000",
    "3. low": "1879.3600",
    "4. close": "1892.5000",
    "5. volume": "893752"
    },
    "2018-08-15 11:30:00": {
    "1. open": "1873.4399",
    "2. high": "1893.3500",
    "3. low": "1873.4399",
    "4. close": "1892.1200",
    "5. volume": "798959"
    },
    "2018-08-15 10:30:00": {
    "1. open": "1905.1899",
    "2. high": "1915.5300",
    "3. low": "1871.0200",
    "4. close": "1871.0200",
    "5. volume": "1614045"
    }
    }
}
"""

结构

struct Stocks: Decodable {

    enum  CodingKeys: String, CodingKey { case timeSeries = "Time Series (60min)"}

    struct TimeSerie: Decodable {
        let close : String

        enum  CodingKeys: String, CodingKey { case close = "4. close" }
    }

    let timeSeries : [String:TimeSerie]
}

struct Price {
    let date : Date
    let price : Double
}

解析

let data = Data(jsonString.utf8)   
let decoder = JSONDecoder()

let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
do {
    let stocks = try decoder.decode(Stocks.self, from: data)
    let result = stocks.timeSeries.map { (key: String, value: Stocks.TimeSerie) -> Price in
        return Price(date: dateFormatter.date(from: key)!, price: Double(value.close)!)
    }.sorted(by: {[=12=].date > .date})

    print(result)
} catch { print(error) }