search result not work went add tableviewcell - ios

Search bar is woking very well until I add custom tableview cell. It breaks when I search a keyword matching with a array. When I search wrong, it doesn't break.
var filteredArray = [String]()
var searchController = UISearchController()
var result = UITableViewController()
override func viewDidLoad() {
super.viewDidLoad()
searchController = UISearchController(searchResultsController: result)
tableView.tableHeaderView = searchController.searchBar
searchController.searchResultsUpdater = self
result.tableView.delegate = self
result.tableView.dataSource = self
result.tableView.register(UITableView.self, forCellReuseIdentifier: "Cell")
}
//config seachbar
func updateSearchResults(for searchController: UISearchController) {
filteredArray = array.filter( { (array : String) -> Bool in
if array.contains(searchController.searchBar.text!)
{
return true
}
else
{
return false
}
})
result.tableView.reloadData()
}
and this is a tableview cellForRow
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SanPhamTableViewCell
// fill data into cell
if tableView == result.tableView
{
cell.name.text = filteredArray[indexPath.row]
cell.img.image = UIImage(named: ArrayImage[indexPath.row])
cell.price.text = ArrayPrice[indexPath.row]
cell.price.isUserInteractionEnabled = false
cell.desc.text = arrayDesc[indexPath.row]
cell.desc.isUserInteractionEnabled = false
}
else
{
cell.name.text = arrayName[indexPath.row]
cell.img.image = UIImage(named: arrayImage[indexPath.row])
cell.price.text = arrayPrice[indexPath.row]
cell.price.isUserInteractionEnabled = false
cell.desc.text = arrayDesc[indexPath.row]
cell.desc.isUserInteractionEnabled = false }
return cell
}

You need to register the cell like this in viewDidLoad, replace:
result.tableView.register(UITableView.self, forCellReuseIdentifier: "Cell")
with:
result.tableView.register(SanPhamTableViewCell.self, forCellReuseIdentifier: "Cell")
//
Edit : for xib
result.tableView.register(UINib(nibName: "SanPhamTableViewCell", bundle: nil), forCellReuseIdentifier: Cell)

I am not sure how are you making the SanPhamTableViewCell, But if you are using a custom nib then that nib must also be registered with tableView
result.tableView.register(UINib(nibName: "SanPhamTableViewCell", bundle: nil), forCellWithReuseIdentifier: "Cell")

Related

custom tableview cell xib outlets returning nil

I have a view controller with a tableview. I want to register my tableview with a custom uitableviewcell that i created programmatically with a xib file. inside the custom cell i have a function that would change the outlets labels values and this is where i am getting a fatal found nil error. here is my code for the view controller.
class AllTasksViewController: UIViewController{
var tableView = UITableView()
func configureTableView(){
view.addSubview(tableView)
setTableViewDelegates()
tableView.rowHeight = 50
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
tableView.register(CustomCellNSB2.self, forCellReuseIdentifier: "CustomCellNSB2")
}
func setTableViewDelegates(){
tableView.delegate = self
tableView.dataSource = self
}
override func viewDidLoad(){
super.viewDidLoad()
configureTableView()
print("allTasksView loaded")
//add some positioning and size constraints here for allTasksView
}
}
extension AllTasksViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allTasks.count
}
// Cell Data and Configuration
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let task = allTasks[indexPath.row] // creating a new task from the already stored task depending on the indexpath.row if indexPath.row is 3 then the task is tasks[3]
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCellNSB2", for: indexPath) as! CustomCellNSB2 // setting the identifier ( we have already set in the storyboard, the class of our cells to be our custom cell)
cell.setTask(task: task) `// this is where my app is crashing`
if (task.value(forKey: "isComplete") as! Bool == true){
cell.labelsToWhite()
cell.backgroundColor = Colors.greencomplete
cell.selectionStyle = .none
} else {
cell.backgroundColor = .white //adjust for nightmode later
cell.labelsToBlack()
}
print("CellData Task :", task.value(forKey: "isComplete") as! Bool, task.value(forKey: "name") as! String)
// if !(task.value(forKey: "isComplete") as! Bool){
// cell.backgroundColor = task.isImportant ? .purple : .white //according to the task isImportant attribute we set the background color
// }
return cell
}
and here is my custom uitableview cell
import UIKit
import CoreData
class CustomCellNSB2: UITableViewCell {
#IBOutlet weak var taskLabel: UILabel!
#IBOutlet weak var dateLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func setTask(task: NSManagedObject ){ debugger leads me here. this is where it's getting nil
taskLabel.text = task.value(forKey: "name") as? String
dateLabel.text = task.value(forKey: "date") as?
String
}
func labelsToWhite() {
taskLabel.textColor = .white
dateLabel.textColor = .white
}
func labelsToBlack() {
taskLabel.textColor = .black
dateLabel.textColor = .red
}
}
You have to register your NIB ... all you are doing is registering the class.
Change this:
tableView.register(CustomCellNSB2.self, forCellReuseIdentifier: "CustomCellNSB2")
to this:
tableView.register(UINib(nibName: "CustomCellNSB2", bundle: nil), forCellReuseIdentifier: "CustomCellNSB2")
If you have the xib/nib configured correctly, that may be all you need to do.

Retrieving textfield data from custom cell from another view outside of the table view

I have a view with an embedded UITableViewController that is filled with custom cells. When I hit the save button I would like the getProjectName() within the UITableViewController to return the projectNameTF data within in the custom cell. Currently when I try to get the cell within the getProjectName() it returns a nil cell.
Main View:
class NewProjectView: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func saveBtn(_ sender: UIButton) {
print("Save button hit")
print(NewProjectTableViewController().getProjectName())
}
}
Embedded TableViewController
import UIKit
struct cellType{
var mainTitle = String()
var numOfChildCells = Int()
var opened = Bool()
}
class NewProjectTableViewController: UITableViewController {
var tableViewData = [cellType]()
var customCellData = [UITableViewCell]()
var projectNameTFR = UITextField()
// Counts the number of cells and displays them
override func numberOfSections(in tableView: UITableView) -> Int {
return tableViewData.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// If the parent cell is opened display the number of cells inside it
if tableViewData[section].opened == true {
return tableViewData[section].numOfChildCells + 1
}
else {
return 1
}
}
//
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
self.tableView.separatorStyle = .none
// Do this for the header cell
if indexPath.row == 0{
guard let cell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell") as? HeaderCell else {return UITableViewCell()}
cell.backgroundColor = .clear
cell.setUpCell(title: tableViewData[indexPath.section].mainTitle)
// If cell should be opened, display correct open image
if tableViewData[indexPath.section].opened{
cell.openCell()
}
// else display closed image
else{
cell.closeCell()
}
return cell
// else it is a child cell
}else {
switch tableViewData[indexPath.section].mainTitle{
// Load Project info cell
case "Project Information":
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ProjectNameCell") as? ProjectNameCell else {return UITableViewCell()}
projectNameTFR = cell.projectNameTF
return cell
case "Client Information":
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ClientInfoCell") as? ClientInfoCell else {return UITableViewCell()}
return cell
default:
print("defaulted cell")
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") else {return UITableViewCell()}
return cell
}
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableViewData[indexPath.section].opened == true{
tableViewData[indexPath.section].opened = false
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .none)
let headerCell = tableView.cellForRow(at: indexPath) as! HeaderCell
}
else{
tableViewData[indexPath.section].opened = true
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .none)
let headerCell = tableView.cellForRow(at: indexPath) as! HeaderCell
}
}
override func viewDidLoad() {
super.viewDidLoad()
//self.definesPresentationContext = true
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = UITableView.automaticDimension
// Do any additional setup after loading the view.
print("add new client screen loaded")
registerTableViewCells()
// Create the cells
tableViewData = [cellType(mainTitle: "Project Information", numOfChildCells: 1, opened: true ),
cellType(mainTitle: "Client Information", numOfChildCells: 1, opened: false )]
}
override func viewWillAppear(_ animated: Bool) {
// Add a background view to the table view
let backgroundImage = UIImage(named: "App Background.png")
let imageView = UIImageView(image: backgroundImage)
self.tableView.backgroundView = imageView
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
private func registerTableViewCells(){
let ClientInfoCell = UINib(nibName: "ClientInfoCell", bundle: nil)
self.tableView.register(ClientInfoCell, forCellReuseIdentifier: "ClientInfoCell")
let ProjectNameCell = UINib(nibName: "ProjectNameCell", bundle: nil)
self.tableView.register(ProjectNameCell, forCellReuseIdentifier: "ProjectNameCell")
let HeaderCell = UINib(nibName: "HeaderCell", bundle: nil)
self.tableView.register(HeaderCell, forCellReuseIdentifier: "HeaderCell")
let SaveCell = UINib(nibName: "SaveCell", bundle: nil)
self.tableView.register(SaveCell, forCellReuseIdentifier: "SaveCell")
}
func getProjectName() -> String{
let indexPath = NSIndexPath(row: 0, section: 0)
let cell = tableView?.cellForRow(at: indexPath as IndexPath) as? ProjectNameCell
print(type(of: cell))
if(cell==nil){
print("cell is nil")
}
return "I returned this test string"
}
}
Custom Cell I am trying to reach
import UIKit
class ProjectNameCell: UITableViewCell {
#IBOutlet weak var projectNameTF: UITextField!
var projectName = String()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
backgroundColor = .clear
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Well sir you are getting cell on index path 0 section number and 0th row
let indexPath = NSIndexPath(row: 0, section: 0)
on that index you have HeaderCell instead of ProjectNameCell thats why you are getting nil
this line can't cast your HeaderCell to ProjectNameCell
let cell = tableView?.cellForRow(at: indexPath as IndexPath) as? ProjectNameCell

How to display search results like the iOS "Contacts" app

I am new iOS programming. I have tried to implement my app to look like the iOS Contacts app. But I have no idea how to implement what I desire. I want to get search results to look like the default iOS app.
Look what I tried so far:
When I type something the dimsBackgroundDuringPresentation is still true.
Here is my expectation:
I am wondering how this app shows results like this.
Here is how i declared UISearchController
lazy var searchController: UISearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.hidesNavigationBarDuringPresentation = false
controller.searchBar.sizeToFit()
controller.searchBar.backgroundColor = UIColor.clear
controller.searchBar.placeholder = "Search"
controller.dimsBackgroundDuringPresentation = true
return controller
})()
Here is how i initialized searchBar to header section of tableView
let searchBar = searchController.searchBar
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
searchBar.delegate = self
tableView.tableHeaderView = searchController.searchBar
Here is function for delegate UISearchResultsUpdating
func updateSearchResults(for searchController: UISearchController) {
if let count = searchController.searchBar.text?.count {
if count > 0 {
filterArray.removeAll(keepingCapacity: false)
var a = [String]()
a = [searchController.searchBar.text!]
filterArray = a
searchController.dimsBackgroundDuringPresentation = false
tableView.reloadData()
}else {
searchController.dimsBackgroundDuringPresentation = true
filterArray.removeAll(keepingCapacity: false)
filterArray = array
tableView.reloadData()
}
}
}
Here is my tableView cell looks like
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.isActive {
return filterArray.count
}else {
return array.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
if searchController.isActive {
cell.textLabel?.text = filterArray[indexPath.row]
}else {
cell.textLabel?.text = array[indexPath.row]
}
return cell
}
Try with these options:
let search = UISearchController(searchResultsController: nil)
self.definesPresentationContext = true
search.dimsBackgroundDuringPresentation = false
navigationItem.searchController = search
navigationItem.hidesSearchBarWhenScrolling = false
Try the code in my repo to see it working just tap a tableview item and it will segue to the second controller where you can see the searchbar and tap it to see if this is what you wanted
github link
if navigationItem.searchController == nil {
if searchController == nil {
searchController = UISearchController(searchResultsController: nil)
searchController?.searchBar.placeholder = "Search"
searchController?.delegate = self
searchController?.searchResultsUpdater = self
searchController?.dimsBackgroundDuringPresentation = false
searchController?.searchBar.searchBarStyle = .minimal
}
self.navigationItem.searchController = searchController
self.navigationItem.hidesSearchBarWhenScrolling = false
}
Use property hidesSearchBarWhenScrolling to make the search bar not scroll up, like the contacts app.

Search Controller no results (blank page)

The basic table shows the results correctly - it work properly.
I have a problem with a table that shows the search results, always returns a white page. (no results) The problem may be two tables in one controller?
What am I doing wrong?
class SearchMagazineViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating {
#IBOutlet var tableView: UITableView!
var resultsController: UITableViewController!
var searchController: UISearchController!
var searchMagazines: [Magazine]?
var latestPub = [Magazine]()
func updateSearchResults(for searchController: UISearchController) {
let searchText = searchController.searchBar.text!
if searchText.count > 0 {
self.searchMagazines = CoreDataHandler.searchMagazine(query: searchText, scope: 0)
}
self.resultsController.tableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
latestPub = CoreDataHandler.latestMagazines() ?? [Magazine]()
resultsController = UITableViewController(style: .plain)
resultsController.tableView.register(UINib(nibName: "searchCell", bundle: nil), forCellReuseIdentifier: "searchCell")
resultsController.tableView.dataSource = self
resultsController.tableView.delegate = self
searchController = UISearchController(searchResultsController: resultsController)
searchController.delegate = self
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = true
navigationItem.searchController = searchController
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.resultsController {
return searchMagazines?.count ?? 0
}else{
return latestPub.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == self.resultsController {
let cell = tableView.dequeueReusableCell(withIdentifier: "searchCell", for: indexPath) as! SearchCell
let item = searchMagazines![indexPath.row]
cell.cat.text = TitleReturn(id: item.cat)
return cell
}else{
guard let cell = tableView.dequeueReusableCell(withIdentifier: "SearchCell") as? SearchTableViewCell else { return UITableViewCell() }
cell.title.text = latestPub[indexPath.row].title
return cell
}
}
}

How could I add UISwitch to Uitableview

I could not find any way to add switch button in my tableview
I have a search bar which works perfectly,
and now I want to add a toggle button to enable "AND" "OR" filter in my search.
import Foundation
import UIKit
class TableViewController: UITableViewController, UISearchResultsUpdating {
var appDel: AppDelegate!
// var customTabBarItem:UITabBarItem = UITabBarItem(title: nil, image: UIImage(named: "my.png")?.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal), selectedImage: UIImage(named: "my.png"))
var filteredTableData = [String]()
var resultSearchController = UISearchController()
override func viewDidLoad() {
self.edgesForExtendedLayout = UIRectEdge.None
UIApplication.sharedApplication().statusBarHidden = true
appDel = UIApplication.sharedApplication().delegate as? AppDelegate
// tabBarItem = customTabBarItem
self.resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
self.tableView.tableHeaderView = controller.searchBar
return controller
})()
// Reload the table
self.tableView.reloadData()
print("TableView called!!")
}
func updateSearchResultsForSearchController(searchController: UISearchController)
{
//refer to http://www.ioscreator.com/tutorials/add-search-table-view-tutorial-ios8-swift
filteredTableData.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = ((appDel.dataFetcher?.appTitles)! as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableData = array as! [String]
self.tableView.reloadData()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (self.resultSearchController.active) {
return self.filteredTableData.count
}
else if appDel.dataFetcher?.appTitles == nil {
return 0
}else{
return (appDel.dataFetcher?.appTitles?.count)!
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("appCell", forIndexPath: indexPath)
let currentItem: String = (appDel.dataFetcher?.appTitles?[indexPath.row])!
if (self.resultSearchController.active) {
cell.textLabel?.text = filteredTableData[indexPath.row]
return cell
}
else {
cell.textLabel?.text = currentItem
cell.detailTextLabel?.text = String(indexPath.row)
return cell
}
}
}
Create a table header view by dragging a UIView to the top of the tableView, just above the first prototype cell. See this question for an example.
There you can place your UISwitchView and create an outlet to your VC.

Resources