2

I use the below to filter my Custom Object Array using a SearchBar.

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
    if searchText != ""
    {
        searchedData = data.filter({ 
            $0.reg?.range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil 
            || $0.type?.range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil 
            || $0.type?.removingSymbols().range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil 
            || $0.reg?.removingSymbols().range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil 
        })
        searching = true
        table1.reloadData()
    }
    else
    {
        searching = false
        table1.reloadData()
    }
}

For the below Class:

class CustomIndex {
   let id: Int64
   let type: String?
   let reg: String?
   init(id: Int64, type: String, reg: String)
   {
       self.id = id
       self.type = type
       self.reg = reg
   }
}

var data: [CustomIndex] = [CustomIndex]()
    
var searchedData: [CustomIndex] = [CustomIndex]()
var searching = false
@IBOutlet weak var dataSearch: UISearchBar!

I need to add a SearchBar to my other table which works the same however my Class Contains an Array which fills the rows and the initial array is for the sections. So i'm not quite sure how to implement this to keep the Sections that contain the text within the section and filter the Array that is within. This is the nested class array:

class RowIndex {
    let date: Date?
    let type: String?
    let reg: String?
    init(date: Date, type: String, reg: String) {
        self.date = date
        self.type = type
        self.reg = reg
    }
}

class SectionIndex {
    let index: Int?
    let title: String?
    let date: Date?
    var data: [RowIndex] = [RowIndex]()
    var minutes: Int?
    init(index: Int, title: String, date: Date, data: [RowIndex], minutes: Int)
    {
        self.index = index
        self.title = title
        self.date = date
        self.data = data
        self.minutes = minutes
    }
}

Which is used for my table:

var array: [SectionIndex] = [SectionIndex]()

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return array[section].data.count
}

func numberOfSections(in tableView: UITableView) -> Int {
    return array.count
}

1 Answer 1

1

I believe it is possible to achieve your goal using your approach and simply adapting your filter logic.

Try creating a method to filter your array of SectionIndex instances:

let array: [SectionIndex] = []

The method loops through each section and filters the rows the same way you did. After that, simply verify if any row matched the search and if it did, create a new SectionIndex copy adding only the rows that matched the search.

func filterSections(with searchText: String) -> [SectionIndex] {
    var searchedData: [SectionIndex] = []

    for sectionIndex in array {
        let filteredRows: [RowIndex] = sectionIndex.data.filter({
               $0.reg?.range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil
            || $0.type?.range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil
            || $0.type?.removingSymbols().range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil
            || $0.reg?.removingSymbols().range(of: searchText, options: [.caseInsensitive, .diacriticInsensitive]) != nil
        })
        
        // Ignore the section if not rows match the search
        if filteredRows.isEmpty { continue }
        
        let newSectionIndex = SectionIndex(
            index: sectionIndex.index!, // TODO: handle the optional value
            title: sectionIndex.title!, // TODO: handle the optional value
            date: sectionIndex.date!, // TODO: handle the optional value
            data: filteredRows,
            minutes: sectionIndex.minutes! // TODO: handle the optional value
        )
        
        searchedData.append(newSectionIndex)
    }

    return searchedData
}

Finally on the search callback:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
    if searchText != ""
    {
        searchedData = filterSections(with: searchText)
        searching = true
        table1.reloadData()
    }
    else
    {
        searching = false
        table1.reloadData()
    }
}

The tableView data source methods would look like something like this:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if searching {
        return searchedData[section].data.count
    } else {
        return array[section].data.count
    }    
}

func numberOfSections(in tableView: UITableView) -> Int {
    if searching {
        return searchedData.count
    } else {
        return array.count
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.