如何使用 Alamofire 和 SwiftyJSON 将 JSON 字典元素中的所有元素附加到数组
How to append all elements from an element of JSON dictionary to an array with Alamofire and SwiftyJSON
我正在尝试追加给定 JSON 字典中可用的从最新到最旧的所有收盘价。我正在使用的 URL 请求如下:
如您所见,结果是一个按最近日期排序的字典,在该字典中,有各种选项,包括收盘价。可以在下面看到它的一点点。
{
"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) }
我正在尝试追加给定 JSON 字典中可用的从最新到最旧的所有收盘价。我正在使用的 URL 请求如下:
如您所见,结果是一个按最近日期排序的字典,在该字典中,有各种选项,包括收盘价。可以在下面看到它的一点点。
{
"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) }