I'm using Alamofire and SwiftyJSON and I'm getting my data, but my view is only repeating the data for the first element of the JSON. The data should be Monday, Tuesday, Wednesday, and so on
[![enter image description here][1]][1]
Here's the class I'm using
class observer : ObservableObject {
@Published var datas = [datatype]()
init() {
AF.request("https://api.npoint.io/e667b934a476b8b88745").responseData { (data) in
let json = try! JSON(data: data.data!)
let trainingDay = json["weekExercise"].arrayValue.map
{$0["exercise"].stringValue}
print(trainingDay)
for i in json["weekExercise"]{
self.datas.append(datatype(id: i.1["weeknumber"].intValue,
day: i.1["day"].stringValue,
exercise: i.1["exercise"].stringValue,
dayMiles: i.1["dayMiles"].intValue))
}
}
}
}
My data looks like this:
{
"weeknumber": 1,
"weekExercise": [
{
"day": "Monday",
"dayMiles": 6,
"exercise": "6 miles"
},
{
"day": "Tuesday",
"dayMiles": 9,
"exercise": "12 x 400m WU/CD"
},
{
"day": "Wednesday",
"dayMiles": 0,
"exercise": "Rest"
},
{
"day": "Thursday",
"dayMiles": 6,
"exercise": "6 miles"
},
{
"day": "Friday",
"dayMiles": 6,
"exercise": "6 miles"
},
{
"day": "Saturday",
"dayMiles": 6,
"exercise": "6 miles"
},
{
"day": "Saturday",
"dayMiles": 8,
"exercise": "8 miles"
}
],
"totalWeekMiles": 41,
"planName": "Hanson Method Advance"
}
[1]: https://i.sstatic.net/9ZlRy.png?s=256
My suggestion is to take advantage of Alamofire's support of Codable
and Combine
. SwiftyJSON is outdated and not needed anymore.
import Combine
import Alamofire
struct ExerciseData : Codable, Identifiable {
let id : Int
let weeknumber : Int
let weekExercise : [Exercise]
}
struct Exercise : Codable, Identifiable {
let id = UUID()
let day: String
let dayMiles: Int
let exercise: String
private enum CodingKeys : String, CodingKey { case day, dayMiles, exercise}
}
class Observer : ObservableObject {
private var subscription : AnyCancellable?
@Published var exercises = [Exercise]()
init() {
subscription = AF.request("https://api.npoint.io/e667b934a476b8b88745")
.publishDecodable(type: [ExerciseData].self, queue: .global())
.result()
.receive(on: DispatchQueue.main)
.map{ result -> [Exercise] in
switch result {
case .success(let data) : return data.first?.weekExercise ?? []
case .failure: return []
}
}
.sink(receiveCompletion: { _ in
self.subscription = nil // this breaks the retain cycle
}, receiveValue: { exercises in
self.exercises = exercises
})
}
}
You can even remove Alamofire in favor of the built-in data task publisher
import Combine
class Observer : ObservableObject {
private var subscription : AnyCancellable?
@Published var exercises = [Exercise]()
init() {
let url = URL(string: "https://api.npoint.io/e667b934a476b8b88745")!
subscription = URLSession.shared.dataTaskPublisher(for: url)
.receive(on: DispatchQueue.main)
.map(\.data)
.decode(type: [ExerciseData].self, decoder: JSONDecoder())
.map{$0.first?.weekExercise ?? []}
.replaceError(with: [])
.sink(receiveCompletion: { _ in
self.subscription = nil
}, receiveValue: { exercises in
self.exercises = exercises
})
}
}
The error handling is rudimentary. It returns an empty array in case of an error.