I'm studying SwiftUI, found a good example from youtube, but I don't get the expected working result. Here's my project on github.
ContentView:
struct ContentView: View {
@ObservedObject var employeeViewModel = EmployeeViewModel()
var body: some View {
Form {
Section {
Button(action: {self.employeeViewModel.recevedEmployeeData()}) {
Text("Get employee name")
}
}
Section {
List(employeeViewModel.publishingNames, id:\.self) { publishedName in
Text("\(publishedName)")
}
}
}
}
}
EmployeeRoot:
// MARK: - EmployeeRoot
struct EmployeeRoot : Codable {
let data : [EmployeeDatum]?
let status : String?
enum CodingKeys: String, CodingKey {
case data = "data"
case status = "status"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
data = try values.decodeIfPresent([EmployeeDatum].self, forKey: .data)
status = try values.decodeIfPresent(String.self, forKey: .status)
}
}
// MARK: - Datum
struct EmployeeDatum : Codable {
let id : String?
let employeeName : String?
let employeeSalary : String?
let employeeAge : String?
let profileImage : String?
enum CodingKeys: String, CodingKey {
case id = "id"
case employeeName = "employee_name"
case employeeSalary = "employee_salary"
case employeeAge = "employee_age"
case profileImage = "profile_image"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decodeIfPresent(String.self, forKey: .id)
employeeName = try values.decodeIfPresent(String.self, forKey: .employeeName)
employeeSalary = try values.decodeIfPresent(String.self, forKey: .employeeSalary)
employeeAge = try values.decodeIfPresent(String.self, forKey: .employeeAge)
profileImage = try values.decodeIfPresent(String.self, forKey: .profileImage)
}
}
EmployeeViewModel:
class EmployeeViewModel: ObservableObject {
@Published var publishingNames: [String] = []
@Published var employeeData: [EmployeeDatum] = []
func recevedEmployeeData() {
WebService.fetchApi()
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
print("finished!")
case .failure(let error):
print("error: ", error)
}
}, receiveValue: { value in
print("receiveValue?: ", value)
self.employeeData = value
for i in self.employeeData {
self.publishingNames = self.publishingNames + [i.employeeName!]
}
})
}
}
WebService:
class WebService {
enum ApiError: Error, LocalizedError {
case unknown, apiError(reason: String)
}
static func fetchApi() -> AnyPublisher<[EmployeeDatum], Error> {
let urlString = "http://dummy.restapiexample.com/api/v1/employees"
guard let url = URL(string: urlString) else {
fatalError("Invalid url")
}
return URLSession.shared.dataTaskPublisher(for: url)
.tryMap { data, response -> Data in
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw ApiError.apiError(reason: "somethink went wrong")
}
return data
}
.decode(type: EmployeeRoot.self, decoder: JSONDecoder())
.map { $0.data! }
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
}
}