I have dynamic table which displays a number of MKMapItems - these items are being displayed by cellForRowAt. But somehow if I click on the cell didSelectRow won't return the map item if I want to print it:
class SearchResultTableViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var visualEffectView: UIVisualEffectView!
private enum SegueID: String {
case showDetail
case showAll
}
private enum CellReuseID: String {
case resultCell
}
private var places: [MKMapItem]? {
didSet {
tableView.reloadData()
}
}
private var suggestionController: SuggestionsTableTableViewController!
var searchController: UISearchController!
private var localSearch: MKLocalSearch? {
willSet {
places = nil
localSearch?.cancel()
}
}
private var boundingRegion: MKCoordinateRegion?
override func awakeFromNib() {
super.awakeFromNib()
...
}
override func viewDidLoad() {
super.viewDidLoad()
...
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if #available(iOS 10, *) {
visualEffectView.layer.cornerRadius = 9.0
visualEffectView.clipsToBounds = true
}
}
...
}
extension SearchResultTableViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return places?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CellReuseID.resultCell.rawValue, for: indexPath)
if let mapItem = places?[indexPath.row] {
cell.textLabel?.text = mapItem.name
cell.detailTextLabel?.text = mapItem.placemark.formattedAddress
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
print(indexPath)
...
guard let mapItem = places?[indexPath.row] else { return }
print(mapItem.name)
...
if tableView == suggestionController.tableView, let suggestion = suggestionController.completerResults?[indexPath.row] {
searchController.isActive = false
searchController.searchBar.text = suggestion.title
search(for: suggestion)
}
}
}
guard let mapItem = places?[indexPath.row] else { return }
- are you sure this guard statement isn't returning?
also, I'm not seeing where you're setting the VC as the tableView delegate/datasource.
Related
I have a Table View that is working fine. However, when I try to implement a UISearchBar and display filtered data, nothing gets filtered. This is my View Controller:
import UIKit
class MealPlanViewController: UIViewController, UISearchBarDelegate {
private var model = MealPlanModel()
private var mealPlan = [MealPlan]()
var filteredData: [MealPlan]!
#IBOutlet weak var topBarStackView: UIStackView!
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
model.delegate = self
searchBar.delegate = self
filteredData = mealPlan
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredData = []
if searchText == "" {
filteredData = mealPlan
}
else {
for item in mealPlan {
if ((item.title?.lowercased().contains(searchText.lowercased())) != nil) {
filteredData.append(item)
}
}
}
self.tableView.reloadData()
}
}
extension MealPlanViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MealPlanCell", for: indexPath) as! MealPlanCell
let filteredMealPlaninTable = filteredData[indexPath.row]
cell.displayMealPlan(filteredMealPlaninTable)
return cell
}
}
extension MealPlanViewController: MealPlanProtocol {
func mealPlansRetrieved(mealPlans: [MealPlan]) {
self.filteredData = mealPlans
tableView.reloadData()
}
}
A couple of notes:
When I run a print(self.filteredData) in my `func mealPlansRetrieved', the console returns all of my data as if it wasn't filtered, but
As soon as I start typing in the search bar, the table view doesn't return any cells, which seems contradictory to the above
For reference, this is the code before filtering that did work:
extension MealPlanViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mealPlan.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MealPlanCell", for: indexPath) as! MealPlanCell
let mealPlanInTable = mealPlan[indexPath.row]
cell.displayMealPlan(mealPlanInTable)
return cell
}
}
extension MealPlanViewController: MealPlanProtocol {
func mealPlansRetrieved(mealPlans: [MealPlan]) {
self.mealPlan = mealPlans
tableView.reloadData()
}
}
Any help/guidance is much appreciated!
Contains returns boolean so this will never fail: item.title?.lowercased().contains(searchText.lowercased())) != nil
To make check work you can simply remove "!= nil".
Im not sure from where you are calling mealPlansRetrieved, but you might want to keep the line "self.mealPlan = mealPlans" instead of "self.filteredData = mealPlans".
I need to call function deleteButtonShowHide, which is in TeamsCell, from TeamsVC, when plusBtnTapped. I am trying to figure it out with protocol TeamsVCDelegate, but it doesn't work( It works vice versa for me. But I do not know how to implement something like cell.teamsCellDelegate = self
TeamsCell
import UIKit
protocol TeamsCellDelegate {
func deleteCell()
}
class TeamsCell: UITableViewCell {
#IBOutlet weak var teamNameLbl: UILabel!
#IBOutlet weak var deleteButton: UIButton!
var teamsCellDelegate: TeamsCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
}
func updateCell(team: team) {
teamNameLbl.text = team.name
}
#IBAction func deleteButtonTapped(_ sender: Any) {
debugPrint("delet tapped")
//deleteButtonShowHide()
findAndDeleteTeam()
teamsCellDelegate?.deleteCell()
}
func findAndDeleteTeam() {
for i in 0...teams.count - 1 {
if teams[i].name == teamNameLbl.text {
teams.remove(at: i)
break
}
}
}
func deleteButtonShowHide(){
if teams.count < 3 {deleteButton.isHidden = true}
if teams.count > 2 {deleteButton.isHidden = false}
}
}
extension TeamsCell: TeamsVCDelegate {
func deleteButtonSH() {
debugPrint("XXX")
deleteButtonShowHide()
}
}
TeamsVC
import UIKit
protocol TeamsVCDelegate {
func deleteButtonSH()
}
class TeamsVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var plusBtn: UIButton!
#IBOutlet weak var teamsTable: UITableView!
var teamsVCDelegate: TeamsVCDelegate?
override func viewDidLoad() {
super.viewDidLoad()
teamsTable.delegate = self
teamsTable.dataSource = self
teamsTable.rowHeight = 55
teamsTable.isScrollEnabled = false
teamsTable.backgroundColor = nil
teamsTable.separatorStyle = .none
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return teams.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "TeamsCell") as? TeamsCell {
cell.updateCell(team: teams[indexPath.row])
cell.teamsCellDelegate = self
return cell
}
return UITableViewCell()
}
#IBAction func plusBtnTapped(_ sender: Any) {
plusBtnHide()
addTeam()
teamsTable.reloadData()
teamsVCDelegate?.deleteButtonSH()
print(teams)
}
func plusBtnShow() {
if teams.count < 5 {plusBtn.isHidden = false}
}
func plusBtnHide() {
if teams.count == 4 { plusBtn.isHidden = true}
}
}
extension TeamsVC: TeamsCellDelegate {
func deleteCell() {
self.teamsTable.reloadData()
self.plusBtnShow()
}
}
You could call deleteButtonShowHide function when you are loading/setting up a cell:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "TeamsCell") as? TeamsCell {
cell.updateCell(team: teams[indexPath.row])
cell.deleteButtonShowHide() // <-- HERE
cell.teamsCellDelegate = self
return cell
}
return UITableViewCell()
}
By the way, your cell should not contain such logic in the first place. It should depend on some data model object which then should be used to setup your cell correctly (show/hide UI elements, etc.).
You could simplify by setting the button show/hide when computing the number of row.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if teams.count < 5 {plusBtn.isHidden = false}
if teams.count == 4 { plusBtn.isHidden = true}
return teams.count
}
And set the delebutton visibility when creating the cell :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "TeamsCell") as? TeamsCell {
cell.updateCell(team: teams[indexPath.row])
// cell.teamsCellDelegate = self
cell.deleteButton.isHidden = (teams.count < 3)
return cell
}
return UITableViewCell()
}
So no need for delegate and cell does not have to know about the model (teams)
I'm trying to show the label with content "aaaaaaaaaaaaaaaaA". I'm using Reusable library. Although I connected IBOutlet right way, the label and imageView of cell did not show content.
This is my cell class
import UIKit
import Reusable
import SDWebImage
protocol ChooseMemberTableViewCellDelegate: AnyObject {
func addUserToGroup(forUser user: User)
}
class ChooseMemberTableViewCell: UITableViewCell, Reusable {
#IBOutlet weak var userImageView: UIImageView!
#IBOutlet weak var userNameLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func setupCell(data: User) {
userNameLabel?.text = "aaaaaaaaaaaaaaaaA"
// userNameLabel?.text = "\(data.userName)"
// let url = URL(string: data.image)
// userImageView.sd_setImage(with: url ?? "", completed: nil)
}
}
This is my ViewController, which i register cell
//
// MembersViewController.swift
// Message
//
// Created by Minh Tâm on 1/9/20.
// Copyright © 2020 Minh Tâm. All rights reserved.
//
import UIKit
import Firebase
import Reusable
import Then
private enum Constants {
static let numberOfSection = 1
static let heightForRows: CGFloat = 60
}
final class ChooseMembersViewController: UIViewController {
#IBOutlet private weak var searchMembers: UISearchBar!
#IBOutlet private weak var listContacts: UITableView!
var searchUser = [User]()
private let database = Firestore.firestore()
var users = [User]()
private var currentUser = Auth.auth().currentUser
private var roomRepository = RoomRepository()
private var userRepository = UserRepository()
var groupName: String?
private var selectUserArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
// userRepository.fetchUser()
configListTableView()
fetchUser()
}
func configListTableView() {
listContacts.do {
$0.register(cellType: ChooseMemberTableViewCell.self)
$0.delegate = self
$0.dataSource = self
}
}
public func fetchUser() {
database.collection("users").getDocuments(){ (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
if let snapshot = querySnapshot {
for document in snapshot.documents {
let data = document.data()
let uid = data["uid"] as? String ?? ""
if uid != self.currentUser?.uid {
let newUser = User.map(uid: uid, dictionary: data)
self.users.append(newUser)
}
}
}
self.searchUser = self.users
self.listContacts.reloadData()
}
}
}
#IBAction func handleBack(_ sender: UIButton) {
self.dismiss(animated: false)
}
#IBAction func handleDone(_ sender: UIButton) {
guard let currentUser = currentUser, let groupName = groupName else { return }
selectUserArray.append(currentUser.uid)
let time = NSNumber(value: Int(NSDate().timeIntervalSince1970))
roomRepository.updateFirebase(groupName: groupName, time: time, selectUserArray: selectUserArray)
}
}
extension ChooseMembersViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.isEmpty {
searchUser = users
} else {
searchUser = users.filter { $0.userName.lowercased().contains(searchText.lowercased()) }
}
listContacts.reloadData()
}
}
extension ChooseMembersViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return Constants.numberOfSection
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchUser.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = listContacts.dequeueReusableCell(for: indexPath, cellType: ChooseMemberTableViewCell.self).then {
let user = searchUser[indexPath.row]
$0.setupCell(data: user)
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return Constants.heightForRows
}
}
extension ChooseMembersViewController: ChooseMemberTableViewCellDelegate {
func addUserToGroup(forUser user: User) {
let selectedUserUid = user.uid
selectUserArray.append(selectedUserUid)
}
}
Cell does not show information of label and imageView
ChooseMemberTableViewCell is correct, but I'd recommend use userNameLabel.text = "aaaaaaaaaaaaaaaaA" (not optional for userNameLabel)
If you use cell from Storyboard into your tableView - no need to register this one, the UIStoryboard already auto-register its cells. I mean you should remove this line: listContacts.register(cellType: ChooseMemberTableViewCell.self)
You should add identifier ChooseMemberTableViewCell for cell in Storyboard
This should work for cellForRowAt:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: ChooseMemberTableViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.setupCell(data: user)
.then {
let user = searchUser[indexPath.row]
$0.setupCell(data: user)
}
return cell
}
I guess that's all. I've done it and I see label with text in tableView
I created a ViewController with a UITableView as a subView.
import UIKit
class ViewController: UIViewController {
private var tableDataSource = [
"Lorem Ipsum is simply du.",
"It is a long established .",
"Lorem Ipsum come",
"All the Lorem .",
"The standard ch.",
"The generated.",
"Various versions."
]
private var isReorderingEnabled = false
private var isDeleteEnabled = false
#IBOutlet private var reorderCellsBarButton: UIBarButtonItem!
#IBOutlet private var selectCellsBarButton: UIBarButtonItem! {
didSet {
selectCellsBarButton.tag = ButtonTags.Select
}
}
#IBOutlet private var deleteCellsBarButton: UIBarButtonItem! {
didSet {
deleteCellsBarButton.tag = ButtonTags.Delete
}
}
#IBOutlet weak private var tableView: UITableView! {
didSet {
tableView.dataSource = self
tableView.delegate = self
tableView.allowsMultipleSelectionDuringEditing = false
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 300
}
}
}
extension ViewController {
private struct ButtonTags {
static let Delete = 2
static let Select = 1
}
private struct LocalizedStrings {
static let EnableReorderingText = "Reorder"
static let DisableReorderingText = "Done"
static let EnableSelectionText = "Select"
static let ConfirmDeletionText = "Delete"
static let DisableDeletionText = "Cancel"
}
}
extension ViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setDeleteBarButton(hidden: true, animated: false)
}
}
// IBActions
extension ViewController {
#IBAction private func reorderCells(_ sender: UIBarButtonItem) {
isReorderingEnabled = !tableView.isEditing
setSelectBarButton(hidden: isReorderingEnabled)
sender.title = isReorderingEnabled ? LocalizedStrings.DisableReorderingText : LocalizedStrings.EnableReorderingText
tableView.setEditing(isReorderingEnabled, animated: true)
tableView.reloadData()
}
#IBAction private func deleteCells(_ sender: UIBarButtonItem) {
isDeleteEnabled = !tableView.isEditing
setDeleteBarButton(hidden: !isDeleteEnabled)
selectCellsBarButton.title = isDeleteEnabled ? LocalizedStrings.DisableDeletionText : LocalizedStrings.EnableSelectionText
if sender.tag == ButtonTags.Delete {
deleteSelectedRows()
}
tableView.allowsMultipleSelectionDuringEditing = isDeleteEnabled
tableView.setEditing(isDeleteEnabled, animated: true)
tableView.reloadData()
}
}
// Custom Helper methods
extension ViewController {
private func setDeleteBarButton(hidden: Bool, animated: Bool = true) {
navigationItem.setRightBarButtonItems([(hidden ? reorderCellsBarButton : deleteCellsBarButton)], animated: animated)
}
private func setSelectBarButton(hidden: Bool, animated: Bool = true) {
self.navigationItem.setLeftBarButton((hidden ? nil : selectCellsBarButton), animated: animated)
}
private func deleteSelectedRows() {
guard let selectedRows = tableView.indexPathsForSelectedRows else { return }
let indexes = selectedRows.map { $0.row }
tableDataSource.remove(indexes: indexes)
tableView.deleteRows(at: selectedRows, with: .fade)
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableDataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let customCell = tableView.dequeueReusableCell(withIdentifier: CustomTableViewCell.identifier, for: indexPath) as! CustomTableViewCell
customCell.setup(content: tableDataSource[indexPath.row], for : indexPath.row)
return customCell
}
}
// pragma - To Select/Edit/Move TableView Cells
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
tableDataSource.move(from: sourceIndexPath.row, to: destinationIndexPath.row)
let reloadingIndexPaths = IndexPath.createForNumbers(from: sourceIndexPath.row, to: destinationIndexPath.row)
DispatchQueue.main.async {
tableView.reloadRows(at: reloadingIndexPaths, with: .none)
}
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
tableDataSource.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .none)
}
}
}
// pragma - Settings for Edit/Move TableViewCell
extension ViewController {
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
print("Edit- \(tableView.isEditing)")
return tableView.isEditing
}
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
print("Move- \(isReorderingEnabled)")
return isReorderingEnabled
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
print("Style- None")
return .none
}
func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
print("indent- \(isDeleteEnabled)")
return isDeleteEnabled
}
}
In this, I have made three bar buttons,one for Reordering , and other two for Deletion and Cancellation.
So, for delete I have provided ability to select multiple rows.
But the problem is, when Reordering selected, the checkbox is still appearing(Not clickable though). And sometimes when Deletion selected, checkbox doesn't appear.
Cannot understand the absurd behaviour. Is this a bug of XCode ? Please help.
Added Content:
CustomTableViewCell class :
import UIKit
class CustomTableViewCell: UITableViewCell {
static let identifier = "customCellIdentifier"
#IBOutlet weak private var titleLabel: UILabel!
#IBOutlet weak private var backgroundImageView: UIImageView!
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
let selectionView = UIView()
selectionView.backgroundColor = UIColor.clear
selectedBackgroundView = selectionView
}
}
extension CustomTableViewCell {
func setup(content: String, for rowNumber: Int) {
titleLabel.text = content
let backgroundImageName = rowNumber % 2 == 0 ? ImageAssetNames.BlueMatte : ImageAssetNames.GreenThreads
backgroundView = UIImageView(image: UIImage(named: backgroundImageName))
}
}
I am creating a custom tableViewController with searchBar. I created a custom cell class "DataCell".
With following code searchBar is not shown and array of label is not displayed.
How can I solve this problem?
import UIKit
class DataCell: UITableViewCell{
#IBOutlet weak var label: UILabel!
}
class SearchController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
var isSearching = false
var data = ["a","b","c","d","e"]
var filterData = [String]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
searchBar.delegate = self
searchBar.returnKeyType = UIReturnKeyType.done
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isSearching{
return filterData.count
}
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "DataCell", for: indexPath) as? DataCell {
let text: String!
if isSearching {
text = filterData[indexPath.row]
} else {
text = data[indexPath.row]
}
return cell
} else {
return UITableViewCell()
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == nil || searchBar.text == ""{
isSearching = false
view.endEditing(true)
tableView.reloadData()
}else {
isSearching = true
filterData = data.filter({$0 == searchBar.text})
tableView.reloadData()
}
}
}
As of iOS 8, you should be using the [UISearchController][1] for which you need to create 2 classes. A SearchController and a ResultsController. We start by creating a common UITableView class:
import UIKit
class DataCell: UITableViewCell {
#IBOutlet weak var label: UILabel!
func configureCell(_ text: String) {
label.text = text
}
}
Then, for the search class:
class SearchController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var searchController: UISearchController!
var resultController: ResultController?
var data = ["a","b","c","d","e"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(TableCell.self, forCellReuseIdentifier: "DataCell")
tableView.register(UINib(nibName: "DataCell", bundle: Bundle.main), forCellReuseIdentifier: "DataCell")
// Search Results
resultController = ResultController()
setupSearchControllerWith(resultController!)
if #available(iOS 9.0, *) {
searchController?.loadViewIfNeeded()
}
tableView.delegate = self
tableView.dataSource = self
resultController.tableView.delegate = self
}
}
extension: SearchController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "DataCell", for: indexPath) as? DataCell {
return cell.configureCell(data[indexPath.row])
} else {
return UITableViewCell()
}
}
}
extension SearchController: UITableViewDelegate {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView == resultController?.tableView {
performSegue(withIdentifier: "DetailView", sender: resultController?.filterData[indexPath.row])
} else {
performSegue(withIdentifier: "DetailView", sender: data[indexPath.row])
}
}
}
extension SearchController: UISearchResultsUpdating,
UISearchControllerDelegate,
UISearchBarDelegate {
func updateSearchResults(for searchController: UISearchController) {
let resultsTable = searchController.searchResultsController as! ResultVC
// resultsTable.query = searchController.searchBar.text!
resultsTable.filterData = data.filter({
$0 == searchController.searchBar.text!
})
resultsTable.tableView.reloadData()
}
func setupSearchControllerWith(_ results: ResultVC) {
// Register Cells
results.tableView.register(TableCell.self, forCellReuseIdentifier: "DataCell")
results.tableView.register(UINib(nibName: "DataCell", bundle: Bundle.main), forCellReuseIdentifier: "DataCell")
// We want to be the delegate for our filtered table so didSelectRowAtIndexPath(_:) is called for both tables.
results.tableView.delegate = self
searchController = UISearchController(searchResultsController: results)
// Set Search Bar
searchController.searchResultsUpdater = self
searchController.searchBar.sizeToFit()
tableView.tableHeaderView = searchController.searchBar
// Set delegates
searchController.delegate = self
searchController.searchBar.delegate = self
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == nil || searchBar.text == ""{
isSearching = false
view.endEditing(true)
tableView.reloadData()
} else {
isSearching = true
filterData = data.filter({$0 == searchBar.text})
tableView.reloadData()
}
}
}
Then, for the ResultsController class:
class ResultController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var filterData = [String]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(TableCell.self, forCellReuseIdentifier: "DataCell")
tableView.register(UINib(nibName: "DataCell", bundle: Bundle.main), forCellReuseIdentifier: "DataCell")
tableView.dataSource = self
}
}
extension ResultController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let rowCount = filterData.count
// When no data insert centered label
if rowCount == 0 {
blankView(with: textForEmptyLabel)
} else {
// Remove empty table label
tableView.backgroundView = nil
tableView.separatorStyle = .singleLine
}
return rowCount
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "DataCell", for: indexPath) as? DataCell {
return cell.configureCell(filterData[indexPath.row])
} else {
return UITableViewCell()
}
}
}