Essentially I am attempting to change a variable when a specific row is selected however, the code is still printing -1. Here is all my code relating. I am trying to be able to click a certain tableview cell and then be able to print out that text. Would the searchBar effect my values? I first code the tableview and then the searchbar and then I implement a submit button which prints the values of my variables.
class ViewController: UIViewController, UITableViewDataSource, UISearchBarDelegate, UITableViewDelegate {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
let Data = ["dog","cat","goat"]
var filteredData: [String]!
var num = -1
var animal: String = ""
override func viewDidLoad() {
super.viewDidLoad()
if tableView != nil {
self.tableView.dataSource = self
}
filteredData = Data
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell
cell.textLabel?.text = filteredData[indexPath.row]
print(indexPath.row)
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredData.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
num = 0
}
if indexPath.row == 1 {
num = 1
}
if indexPath.row == 2 {
num = 2
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredData = searchText.isEmpty ? Data : Data.filter { (item: String) -> Bool in
// If dataItem matches the searchText, return true to include it
return item.range(of: searchText, options: .caseInsensitive, range: nil, locale: nil) != nil
}
tableView.reloadData()
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
self.searchBar.showsCancelButton = true
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.showsCancelButton = false
searchBar.text = ""
searchBar.resignFirstResponder()
}
#IBAction func Submit(_ sender: Any) {
print(num)
print(filteredData.count)
if num == 0 {
animal = "dog"
}
if num == 1 {
animal = "cat"
}
if num == 2 {
animal = "goat"
}
print(animal)
}
}
There are a few issues that are not allowing you to achieve what you want:
The == operator is checking if two variables are equal to each other, not assigning one variable to another, and it will return a boolean value, either true or false. In the body of your if statements, change == to = to assign a value to the variable num.
Change your code to:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
num = 0
}
if indexPath.row == 1 {
num = 1
}
if indexPath.row == 2 {
num = 2
}
}
After seeing your updated code, it looks like you only set the dataSource of the tableView and not the delegate. You need to add the line to viewDidLoad:
tableView.delegate = self
Also, instead of having multiple if statements to check the indexPath, you could replace that entire body of code with one line:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
num = indexPath.row
}
Related
When I press odd it shows true or false. How can Get values of array I'm trying to print odd value when i tap odd on segment or even values when i tap even , How can get this. I'm new in ios. Please help
class ViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var segmentOutlet: UISegmentedControl!
let numberArray = Array(1...100)
var segmentIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
}
#IBAction func segmentControl(_ sender: UISegmentedControl) {
tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : TableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
cell.numberLbl.text = String(numberArray[indexPath.row])
if segmentOutlet.selectedSegmentIndex == 1 {
cell.numberLbl.text = String(numberArray[indexPath.row] % 2 == 0)
}
if segmentOutlet.selectedSegmentIndex == 2 {
cell.numberLbl.text = String(numberArray[indexPath.row] % 2 == 1)
}
return cell
}
}
my Simulator image:
Your numberArray[indexPath.row] % 2 == 0 has a ==, which evaluates to true/false. It doesn't really make sense. Also, there's no need to check if the current indexPath.row is odd or even... you're trying to display a list of even or odd numbers, so what does indexPath.row have to do with that?
Instead, try making a second array, filteredArray. This will be where the table view directly gets its data from.
let numberArray = Array(1...100)
lazy var filteredArray: [Int] = { numberArray }() /// return `numberArray` by default
You can then update filteredArray based on the selectedSegmentIndex.
#IBAction func segmentControl(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 1: /// even numbers
filteredArray = numberArray.filter { $0 % 2 == 0}
case 2: /// odd numbers
filteredArray = numberArray.filter { $0 % 2 == 1}
default: /// all numbers
filteredArray = numberArray
}
tableView.reloadData()
}
Finally, just read from filteredArray in your data source methods.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredArray.count /// use `filteredArray`
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: TableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
cell.numberLbl.text = String(filteredArray[indexPath.row]) /// also use `filteredArray`
return cell
}
currently I am trying to implement my search bar, but something is wrong and I can't figure it out what it is. Here is the code, and explanation.
//global variable for empty array, its type of Any cause I am getting data from network call
var filteredData: [Any]!
//these are my models, which I am using to display them on screen after mapping in network function
var bookedTrips: [BookedTripsForView]?
func viewDidLoad() {
super.viewDidLoad()
filteredData = bookedTrips
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchBar.becomeFirstResponder()
filteredData = []
if searchText == "" {
filteredData = bookedTrips
}else {
for trip in (bookedTrips)! {
if trip.tripName.lowercased().contains(searchText.lowercased()){
filteredData.append(trip)
//if I type, lets say Barcelona, in console its printed correct result,
//but its displaying only first trip in my array, which is Berlin
print("filteredDataArray after appending print: \(String(describing: filteredData))")
}
}
}
self.tableView.reloadData()
}
I hope that my explanation is ok, if something's not clear, I will refactor my question. Thanks in advance.
Here is picture of my screen and console
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let filter = filteredData {
return filter.count
} else if let data = bookedTrips {
return data.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Cells.tripInfo) as! TripsListDetailCell
if let trips = bookedTrips?[indexPath.row] {
cell.configure(trips: trips)
}
return cell
}
Short and simple (One line filter)
var filteredData = [BookedTripsForView]()
var bookedTrips = [BookedTripsForView]()
override func viewDidLoad() {
super.viewDidLoad()
bookedTrips = fetchFromAPIorDB()
filteredData = bookedTrips
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.filteredData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Cells.tripInfo) as! TripsListDetailCell
cell.configure(trips: filteredData[indexPath.row])
return cell
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.isEmpty {
filteredData = bookedTrips
}
else {
filteredData = bookedTrips.filter({ $0.tripName.lowercased().contains(searchText.lowercased()) })
}
self.tableView.reloadData()
}
var isSearching: Bool = false // As global variable
var bookedTrips: [BookedTripsForView]? = []
var filteredData: [BookedTripsForView]? = []
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchBar.becomeFirstResponder()
filteredData = []
if searchText == "" {
isSearching = false
}else {
isSearching = true
filteredData = bookedTrips.filter { (trip) -> Bool in
if trip.tripName.lowercased().contains(searchText.lowercased()){
return true
}
return false
}
}
self.tableView.reloadData()
}
//Tableview delegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isSearching {
return self.filteredData.count
}
return bookedTrips.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Cells.tripInfo) as! TripsListDetailCell
if isSearching {
cell.configure(trips: filteredData[indexPath.row])
}
else {
cell.configure(trips: bookedTrips[indexPath.row])
}
return cell
}
create enum for page mood like this for readable code:
enum PageMood {
case normal
case search
}
and create variable
var pageMode: PageMood = .normal
set normal for first first if search and change pageMode to search like this:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchBar.becomeFirstResponder()
if searchText == "" {
pageMode = .normal
}else {
pageMode = .search
filteredData = bookedTrips?.filter({ item -> Bool in
return (item.tripName?.lowercased().contains(searchText.lowercased()) ?? false)
})
}
self.tableView.reloadData()
}
change define datasource like this:
var bookedTrips: [BookedTripsForView]?
var filteredData: [BookedTripsForView]?
and inside set numberOfItem:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if pageMode == .search {
return filteredData.count ?? 0
} else {
return bookedTrips.count ?? 0
}
}
if only one item find، Maybe your data has only one item similar to the search text.
And now, since I changed my variables to this :
var filteredData = [BookedTripsForView]()
var bookedTrips = [BookedTripsForView]()
I have one more problem in sections, added comment inside
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableHeaderFooterView(withIdentifier: Cells.sectionTitle) as! TripsListHeaderCell
if isSearching {
cell.configure(trips: filteredData[section])
}
else {
cell.configure(trips: bookedTrips[section])
}
return cell
}
How should I implement function viewForHeaderInSection? In response inside every trip I get status of trip (current, upcoming, previous). I would like to sort them by status. If I put this inside viewForHeaderInSection :
if isSearching {
cell.configure(trips: filteredData[section])
} else {
cell.configure(trips:bookedTrips[section])
}
return cell
I get index out of range on bookedTrips[section] If i comment that line, it works until I make mistake in search bar, lets say instead of Barcelona I type Bars, it throws error on filteredData[section] index out of range
In my response, every trip have trip status property which has type string, can I even sort them by that property?
This is an example to explain a problem that I’m having.
I have 3 elements in an array. the index of the array matches each sentences. Like
The 0 index matches “hello” (0 index)
The 1 index matches “nice” (1 index)
The 2 index matches “how are you?” (2 index)
I’ve put UISearchBar in my tableView. When I type “h” in the searchBar, “hello” and “how are you” show up perfectly, but the thing is, when I touch “how are you” which is 2 index on the tableview list, it shows “nice” on the next viewController (I have two viewControllers and the variable called myIndex use the index on the next viewController ) because the variable gets 1 index not 2 index. How should I solve this?
The full code is as follows :
import UIKit
class tableviewtest: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var searchBar: UISearchBar!
func tableView(_ tableView: UITableView,
moveRowAt sourceIndexPath: IndexPath,
to destinationIndexPath: IndexPath) {
}
var searchArr = [String]()
var searching = false
var copiedArray:[String] = eng // eng is the original array that has the full elements from another view controller.
let cellIdentifier = "xxx"
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = self.tableview.dequeueReusableCell(withIdentifier: cellIdentifier, for:indexPath)
if searching {
cell.textLabel?.text = searchArr[indexPath.row]
}
else {
cell.textLabel?.text = copiedArray[indexPath.row]
}
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return searchArr.count
}
else {
return copiedArray.count
}
}
func tableView(_ tableview: UITableView, didSelectRowAt indexPath: IndexPath) {
myIndex = indexPath.row
performSegue(withIdentifier: "segue1", sender: self)
}
#IBOutlet weak var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableview.delegate = self
tableview.dataSource = self
self.tableview.register(UITableViewCell.self,forCellReuseIdentifier: cellIdentifier)
}
}
extension tableviewtest: UISearchBarDelegate {
func searchBar (_ searchBar:UISearchBar, textDidChange searchText: String) {
searchArr = copiedArray.filter({$0.prefix(searchText.count) == searchText})
searching = true
tableview.reloadData()
}
}
At the moment you get the string from the array you have to consider the searching state
let selectedItem = searching ? searchArr[myIndex] : filteredArr[myIndex]
and you have to reset searching if the search string is empty
func searchBar (_ searchBar:UISearchBar, textDidChange searchText: String) {
if searchText.isEmpty {
searching = false
searchArr.removeAll()
} else {
searchArr = filteredArr.filter({$0.prefix(searchText.count) == searchText})
searching = true
}
tableview.reloadData()
}
You could even pass the string as sender parameter in performSegue and hand it over to the next view controller in prepare(for segue
func tableView(_ tableview: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedItem = searching ? searchArr[indexPath.row] : filteredArr[indexPath.row]
performSegue(withIdentifier: "segue1", sender: selectedItem)
}
Side note:
Reconsider your naming of the variables: Why is the data source array once called filteredArr and then numberOfRows, and why is the non-filtered array called filteredArr anyway?
How do I get the correct viewcontroller after selecting a tableview cell can you please help me I think there is a problem with my index
import UIKit
var NamesC = [ "one", "two"]
var IndexC = 0
class ComputerVC: UIViewController ,UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate{
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var TableView: UITableView!
var data = [ "one", "two"]
var filteredData = [String]()
var inSearchMode = false
override func viewDidLoad() {
super.viewDidLoad()
TableView.delegate = self
TableView.dataSource = self
searchBar.delegate = self
searchBar.returnKeyType = UIReturnKeyType.done
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if inSearchMode {
return filteredData.count
}
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? DataCellC {
let text: String!
if inSearchMode {
text = filteredData[indexPath.row]
} else {
text = data[indexPath.row]
}
cell.congigureCell(text: text)
return cell
} else {
return UITableViewCell()
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == nil || searchBar.text == "" {
inSearchMode = false
view.endEditing(true)
TableView.reloadData()
} else {
inSearchMode = true
filteredData = data.filter({$0.contains(searchBar.text!)})
TableView.reloadData()
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
IndexC = indexPath.row
performSegue(withIdentifier: "segue", sender: self)
}
}
You can try
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
var text = ""
if inSearchMode {
text = filteredData[indexPath.row]
let correctIndex = data.index(of:filteredData[indexPath.row])
print("selected value is : \(correctIndex)")
} else {
text = data[indexPath.row]
}
performSegue(withIdentifier: "segue", sender: text)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let secondController = segue.destination as? SecondController {
secondController.sendedValue = sender as! String
}
}
class secondController:UIViewController
{
var sendedValue:String?
}
Issue is here:
Name.text = NamesC[IndexC]
Your array is filtered, your indexC is the one you used in the filtered array.
You can define a filtered array FNamesC, and update this array when you search in your search bar and in your viewController
Name.text = FNamesC[IndexC]
I don't know why you want a global array though.
In Class
class Objects {
var number: Int!
var name: String!
init(number: Int, name: String) {
self.number = number
self.name = name
}
}
In viewController
var allObjects = [Objects]()
var inSearchMode = false
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! Cell
if inSearchMode {
let fill: Objects!
fill = filteredObject[indexPath.row]
cell.configureCell(fill)
} else {
let fill: Objects!
fill = allObjects[indexPath.row]
cell.configureCell(fill)
return cell
}
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if inSearchMode {
return filteredObject.count
}
return allObjects.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == nil || searchBar.text == "" {
inSearchMode = false
tableView.reloadData()
view.endEditing(true)
} else {
inSearchMode = true
var lowerCase = Int(searchBar.text!)
filteredObject = allObjects.filter({$0.number == lowerCase})
tableView.reloadData()
print(filteredObject)
}
}
I would like to have a search bar that filters and shows only one result that contains the number we are looking for. I thought about using contains and put the number we input from the search bar.
I manage to get one object into the filteredObject, but it won't show up in the tableView
Look carefully at this part of your code:
if inSearchMode {
let fill: Objects!
fill = filteredObject[indexPath.row]
cell.configureCell(fill)
} else {
let fill: Objects!
fill = allObjects[indexPath.row]
cell.configureCell(fill)
return cell
}
You did not return a cell when you are in search mode, that is why you do not see anything when searching.
I would use a computed property to drive the tableview; This property is either all the objects or the filtered object(s):
var allObjects = [Objects]()
var filteredObjects: [Objects]?
var objects: [Objects] = {
return filteredObjects ?? allObjects
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.objects.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! Cell
let fill = self.objects[indexPath.row]
cell.configureCell(fill)
return cell
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == nil || searchBar.text == "" {
self.filteredObjects = nil
} else {
var lowerCase = Int(searchBar.text!)
self.filteredObjects = allObjects.filter({$0.number == lowerCase})
}
tableView.reloadData()
}