Im trying to put checkmarks after doing a search. I've seen some answers here but it doesn't work for me. Ive tried some of the answers but it will only make an error.
Here's the code that I wrote.
struct finalCheckednames { var name: String; var checkMark: Bool}
class ShowBroadcastNamesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
var nameslist = ["Mark","Chris", "James", "Sandra"]
var myIndex = 0
var nameArray = String()
var filteredData = [String]()
var isSearching = false
var selectedNamesToBroadcast = [String]()
var selectedNamesIndex:Int? = nil
var checkmarks = [Int : Bool]()
var hasChecked = Bool()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? broadcastNamesTableViewCell {
let text: String!
if isSearching {
text = filteredData[indexPath.row]
} else {
text = nameslist[indexPath.row]
}
cell.configureCell(text: text)
if checkmarks[indexPath.row] != nil {
cell.accessoryType = checkmarks[indexPath.row]! ? .checkmark : .none
} else {
checkmarks[indexPath.row] = false
cell.accessoryType = .none
}
return cell
} else {
return UITableViewCell()
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if isSearching {
selectedNamesIndex = filteredData[indexPath.row] // im also getting an error here
} else {
selectedNamesIndex = indexPath.row
let cell = tableView.cellForRow(at: indexPath)
if let index = selectedNamesIndex {
if (cell?.accessoryType == .checkmark) {
cell!.accessoryType = .none
checkmarks[indexPath.row] = false
hasChecked = false
let indexPathTapped = tableView.indexPath(for: cell!)
let name = nameslist[(indexPathTapped!.row)]
print(name, hasChecked)
if let index = selectedNamesToBroadcast.index(of: name) {
selectedNamesToBroadcast.remove(at: index)
}
} else {
cell!.accessoryType = .checkmark
checkmarks[indexPath.row] = true
hasChecked = true
let indexPathTapped = tableView.indexPath(for: cell!)
let name = nameslist[(indexPathTapped!.row)]
print(name, hasChecked)
selectedNamesToBroadcast.append(name)
let selectedNamesToBroadcast = name
finalCheckednames(name: name, checkMark: hasChecked)
print(finalCheckednames.self, "XXXX")
}
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == nil || searchBar.text == "" {
isSearching = false
view.endEditing(true)
tableView.reloadData()
} else {
isSearching = true
filteredData = namelist.filter{$0.range(of: searchText, options: .caseInsensitive) != nil}
tableView.reloadData()
I was hoping for the checkmarks to stay after searching. So atleast i can save all the checkmarked items somewhere.
Your code is very, very, very complicated. The most efficient way to accomplish your request is to use the isChecked
information in the struct, nothing else, no extra arrays, dictionaries, properties.
Give the struct and the Bool a more meaningful name.
struct Person {
let name: String
var isChecked: Bool
}
In the controller name the data source array people
and the filter array filteredPeople
. Further you need only isSearching
, delete all other properties
class ShowBroadcastNamesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
var people = [Person(name: "Mark", isChecked: false),
Person(name: "Chris", isChecked: false),
Person(name: "James", isChecked: false),
Person(name: "Sandra", isChecked: false)]
var filteredPeople = [Person]()
var isSearching = false
var myIndex = 0
var nameArray = String()
var filteredData = [String]()
var selectedNamesToBroadcast = [String]()
var selectedNamesIndex:Int? = nil
var checkmarks = [Int : Bool]()
var hasChecked = Bool()
In cellForRow
force unwrap the custom cell and name it uppercased (good practice). Pass the name
to configureCell
and set the accessory view depending on the value of isChecked
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! BroadcastNamesTableViewCell
let person = isSearching ? filteredPeople[indexPath.row] : people[indexPath.row]
cell.configureCell(text: person.name)
cell.accessoryType = person.isChecked ? .checkmark : .none
return cell
}
In didSelectRow
toggle isChecked
(and update also the people
array if necessary) and reload the row, that's all
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if isSearching {
filteredPeople[indexPath.row].isChecked.toggle()
let index = people.firstIndex{$0.name == filteredPeople[indexPath.row].name}!
people[index].isChecked.toggle()
} else {
people[indexPath.row].isChecked.toggle()
}
tableView.reloadRows(at: [indexPath], with: .automatic)
}
In textDidChange
search for the name
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.isEmpty {
isSearching = false
filteredPeople.removeAll()
view.endEditing(true)
} else {
isSearching = true
filteredPeople = people.filter{$0.name.range(of: searchText, options: .caseInsensitive) != nil}
}
tableView.reloadData()
}
In this answer I already suggested a more efficient version of textDidChange
, please consider to follow the advices.
To get the checked people just write
let checkedPeople = people.filter{$0.isChecked}