0

I finally have working code to search an array of objects but it's really slow to populate/show the list results in a view. I've been looking into using ObservableObject and EnvironmentObject but I'm not sure how to implement them here. I'm importing a CSV and using the headers as keys and row items as values then displaying them in a List. When I try to search for something the list repopulates but takes a VERY long time. Any help would be greatly appreciated!!!

ListView.swift

import Foundation
import SwiftUI

var arrayOfData = [Container]()
struct ListView: View {


@State private var searchTerm: String = ""
@State private var array: [Container] = []
    //@State var array: [Container] = newArray
        func arrayFiller(){
        if arrayOfData.count > 0 {
            arrayOfData.removeAll()
        }

        for item in csvArray {
            arrayOfData.append(Container(
                barcode: item["Barcode"],
                model: item["Model"],
                description: item["ASDescription"],
                serial: item["Asset Serial No"],
                building: item["Building"],
                floor: item["Floor"],
                room: item["Room"]))
        }

    }

    init() {
       // UITableView.appearance().separatorColor = .clear
        //Build list of headers using the top view.
        arrayFiller()
      }



    var body: some View {


        List {
            SearchBar(text: $searchTerm, array: $array)
            ForEach(array, id:\.self){item in
            Text("\(item.barcode ?? "")")}
            }
        }
}

SearchBar.swift


struct SearchBar: UIViewRepresentable {
    @Binding var text: String
    @Binding var array: [Container]
    class Coordinator: NSObject, UISearchBarDelegate, ObservableObject {

        @Binding var text: String
        @Binding var array: [Container]

        init(text: Binding<String>, array: Binding<[Container]>) {
            _text = text
            _array = array
        }

         func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        text = searchText
        array = [Container]()
      DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
        self.array = arrayOfData.filter {
            self.text.isEmpty ? true : (($0.barcode?.localizedCaseInsensitiveContains(self.text))!)}
            }
            print(array)

        }
    }
    func makeCoordinator() -> SearchBar.Coordinator {
        return Coordinator(text: $text, array: $array)
    }

    func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
        let searchBar = UISearchBar(frame: .zero)
        searchBar.delegate = context.coordinator
        return searchBar
    }

    func updateUIView(_ uiView: UISearchBar, context: UIViewRepresentableContext<SearchBar>) {
        uiView.text = text

    }
}
Mdoyle1
  • 121
  • 1
  • 12
  • Filtering on every view update it is heavy, it is better to do it on `SearchBar` input update (even with debounce) and store it in dedicated state, which would be used in `ForEach` – Asperi Dec 13 '19 at 08:02
  • Thanks for the info... I feel like I'm getting closer. I'm able to update the array quickly but the view never updates. Any Ideas? – Mdoyle1 Dec 13 '19 at 14:58
  • Needed minimal testable code snapshot – Asperi Dec 13 '19 at 15:42
  • @Asperi, Thanks for pointing me in the right direction of filtering in SearchBar my issue has been resolved. The working code is posted above! – Mdoyle1 Dec 16 '19 at 03:22

1 Answers1

2

UPDATE

I was able to resolve the issue with help from this thread... Efficiently Filter a Long List, SwiftUI

The magic happens in the SearchBar function

     DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
        self.array = arrayOfData.filter {
            self.text.isEmpty ? true : (($0.barcode?.localizedCaseInsensitiveContains(self.text))!)}
            }     

After creating the @Binding var array and adding DispatchQueue to the filter method in SearchBar.swift everything I'm now able to search for a item and have the list results populate in realtime. The working code is posted up top in ListView.swift and SearchBar.swift.

Mdoyle1
  • 121
  • 1
  • 12