Posts

Post not yet marked as solved
8 Replies
4k Views
I am building an app using SwiftUI that should display work orders I get from a web service. I have successfully got them from a web service using the following function:func getAllWorkOrders(completion: @escaping ([WorkOrder]) -> ()) { guard let url = URL(string: "http://somedomain/api/workOrders") else { fatalError("URL is not correct") } let conn = URLSession(configuration: URLSessionConfiguration.ephemeral, delegate: self, delegateQueue: nil) conn.dataTask(with: url) { data, _, _ in let decoder = JSONDecoder() decoder.dateDecodingStrategy = .formatted(DateFormatter.iso8601Full) let workOrders = try! decoder.decode([WorkOrder].self, from: data!) DispatchQueue.main.async { completion(workOrders) } }.resume() }while my WorkOrder struct look like this:struct WorkOrder: Identifiable, Codable { var id: Int var ticket: Int? var date: Date var description: String var astue: Bool var state: WorkOrderState var jobs: [WorkOrderJob] var project: Project }I have also created a view model which looks like this:class WorkOrderListViewModel: BindableObject { var workOrders = [WorkOrder]() { didSet { didChange.send() } } var astue = false { didSet { didChange.send() } } var workOrderState = 0 { didSet { didChange.send() } } var searchTerm = "" { didSet { didChange.send() } } var filteredWorkOrders: [WorkOrder] { var filtered = workOrders if astue { filtered = filtered.filter { $0.astue == true } } if workOrderState > 0 && workOrderState < 5 { filtered = filtered.filter { $0.state.id == workOrderState } } if !searchTerm.isEmpty { filtered = filtered.filter { $0.description.lowercased().contains(searchTerm.lowercased()) || "\($0.ticket ?? 0)".contains(searchTerm.lowercased()) } } return filtered } init() { fetchWorkOrders() } func fetchWorkOrders() { WebService().getAllWorkOrders { self.workOrders = $0 } } let didChange = PassthroughSubject<Void, Never>() }In it, I have a couple of filtering criteria: searchTerm, workOrderState and astue. I have a filtering view bound to those 3 properties. Given that web service is quite primitive and there is no paging or filtering (which means that I can get only all work orders, approximately 2k of them), and I need to filter them by one or many of the criteria, I have a calculated propery filteredWorkOrders in the view model which does the required filtering. My problem arises when I do some filtering. In UI, a have a TextField bound to searchTerm, SegmentedControl bound to workOrderState and Toogle bound to astue. When I apply one of the filtering criteria which drastically changes the number of records (for example when switching from workOrderState=0 to workOrderState=1 where it goes from 2k to just 50), UI gets unresponsive and the filtering lasts 6-7 seconds. However, when changes aren't that dramatic (adding astue=true which makes count of work orders go from 50 to 5) it happens in an instant.SwiftUI view for the list and a row look like this:struct WorkOrders : View { @ObjectBinding var data = WorkOrderListViewModel() var body: some View { List { SearchField(data: data) ForEach(self.data.filteredWorkOrders) { workOrder in NavigationLink(destination: WorkOrderDetails(workOrder: workOrder)) { WorkOrderRow(workOrder: workOrder) } } } .listStyle(.grouped) .navigationBarTitle(Text("Work orders (\(String(format: "%d", data.filteredWorkOrders.count)))"), displayMode: .large) .navigationBarItems(trailing: Button(action: refresh) { Image(systemName: "arrow.clockwise") }) } private func refresh() { data.fetchWorkOrders() } }struct WorkOrderRow : View { @State var workOrder: WorkOrder var body: some View { HStack { ZStack { Circle() .fill(backgroundColor()) .frame(width: 20, height: 20, alignment: Alignment(horizontal: .leading, vertical: .center)) } VStack(alignment: .leading) { HStack { if workOrder.astue { Image(systemName: "bolt.fill") } Text(String(format: "%d", workOrder.ticket ?? 0)) .font(.caption) Spacer() Image(systemName: "calendar") Text(workOrder.dateString) .font(.caption) } Text(workOrder.description) .lineLimit(nil) } .padding([.horizontal]) } } private func backgroundColor() -> Color { switch workOrder.state.id { case 1: return Color.red case 2: return Color.yellow case 3: return Color.green case 4: return Color.blue default: return Color.clear } } }What am I missing?
Posted
by iznenada.
Last updated
.