'else' statement not running in 'didSelectRowAt' function while executing - ios

don't know whether it is common or not but in 'didSelectRowAt' function, 'if' statement is executing perfectly but 'else' statement is not and whenever i tap on the cell the checked property is always true down below is the code which might help :-
here is the code :-
import UIKit
import Alamofire
import SwiftyJSON
class TableViewController: UITableViewController {
var vCData = [Item]()
let url = "https://api.coinmarketcap.com/v1/ticker/"
var items = [Item]()
override func viewDidLoad() {
super.viewDidLoad()
getCoinData(url: url)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
let arrayItem = items[indexPath.row]
cell.textLabel?.text = arrayItem.name
cell.detailTextLabel?.text = arrayItem.symbol
if arrayItem.checked == true{cell.accessoryType = .checkmark}
else{cell.accessoryType = .none}
return cell
}
THIS IS WHERE PROBLEM OCCURS :-
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
var selItem = items[indexPath.row]
if selItem.checked == false {
selItem.checked = true
vCData.append(selItem)
}else { // statement not working
selItem.checked = false
if let index : Int = self.vCData.index(where: {$0.name == selItem.name && $0.checked == selItem.checked && $0.buyPrice == selItem.buyPrice && $0.rank == selItem.rank && $0.symbol == selItem.symbol}) {
self.vCData.remove(at: index)
print(vCData,"\n")
}
}
tableView.reloadData()
}
#IBAction func doneTapped(_ sender: UIBarButtonItem) {
self.dismiss(animated: true, completion: nil)
}
}

Assuming Item is a struct and not a class, your issue is the result of the fact that struct is a value type and copies are made when you assign from one variable to another.
In didSelectRowAt you update selItem but this does not change the copy stored in items.
The fix is simple. After your if/else, update items with the new selItem:
items[indexPath.row] = selfItem
On an unrelated note, I would replace the use of reloadData in didSelectRowAt with:
tableView.reloadRows(at: [ indexPath ], with: .fade)
No need to reload the whole table just to update one row.

Related

When I tapped segment Odd or even I am getting true and false value in Tableview instead of odd value or even value

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
}

Filtering query for Realm

I have a function which prints all the objects in my realm table to a table view. I would like to be able to filter these objects by their "muscle" property.
Here's my DB helper functions:
func getMusclesCount()-> Int {
let storedExercise = realm.objects(StoredExercise.self)
return storedExercise.count
}
//MARK:- getAllMuscelsNames
func getAllMusclesNames()-> [String] {
var musclesName = [String]()
let storedExercise = realm.objects(StoredExercise.self)
for exercise in storedExercise {
print("Muscle = \(exercise.muscle)")
musclesName.append(exercise.name)
}
return musclesName
}
Here's my Table View Controller class :
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return DBHelper.shared.getAllMusclesNames().count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
}
let muscle = DBHelper.shared.getAllMusclesNames()[indexPath.row]
cell.textLabel?.text = muscle
return cell
}
I've tried adding .Filter to 'let storedExercise' but I'm not sure how to set it up correctly. Any assitance would be greatly appreciated, thanks.
If your StoredExercise model looks like this
class StoredExercise: Object {
#objc dynamic var muscle = ""
}
then to get all of the exercises that are for the biceps, it's this
let bicepResults = realm.objects(StoredExercise.self).filter("muscle == 'biceps'")

getting the wrong index when I search something on the searcher

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?

Swift 3.0 multiple selection with select all cell

I have added data in table view and I have manually added "select all" option to the list at first position, now when the user selects the first option which is 'select all' then the person manually option "Select all" is not selected. Select all, click then work all person or deselect working but signal selection all the person not working "Select all"
I have tried the code below but it's not working so can any one help me to solve this?
var unchecked:Bool = true
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// create a new cell if needed or reuse an old one
let cell = ObjTableview.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SelectUserCell
// set the text from the data model
cell.selectionStyle = UITableViewCellSelectionStyle.none
cell.lblStudentName.text = getStudentName[indexPath.row]
if UnAll == "unselect" {
if indexPath.row == 0 {
cell.btnCheckbox.setImage(UIImage(named: "unSelectedItem"), for: .normal)
}
if indexPath.row == Int(selectedNumber) {
cell.btnCheckbox.setImage(UIImage(named: "unSelectedItem"), for: .normal)
}
if indexPath.row == Int(unSelectNumber) {
//var j = "\(i)"
cell.btnCheckbox.setImage(UIImage(named: "selectedItem"), for: .normal)
}
}else
{
if(unchecked){
cell.btnCheckbox.setImage(UIImage(named: "unSelectedItem"), for: .normal)
}
else{
cell.btnCheckbox.setImage(UIImage(named: "selectedItem"), for: .normal)
}
}
return cell
}
var UnAll = ""
var selectedNumber = ""
var unSelectNumber = ""
var checkselect:Bool = true
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
UnAll.removeAll()
selectedNumber.removeAll()
unSelectNumber.removeAll()
if(indexPath.row == 0){
btnCheckBoxClick(sender: UIButton())
}else
{
UnAll = "unselect"
btnCheckBoxClick(sender: UIButton())
if checkselect {
selectedNumber = "\(indexPath.row)"
checkselect = false
}else
{
unSelectNumber = "\(indexPath.row)"
checkselect = true
}
print("the selected index is : \(indexPath.row)")
}
}
#IBAction func btnCheckBoxClick(_ sender: Any) {
if(unchecked){
unchecked = false
}
else{
unchecked = true
}
ObjTableview.reloadData()
}
Create a struct for model data with a Bool property. You can modify this property by cell selection.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var allCharacters:[Character] = []
override func viewDidLoad() {
super.viewDidLoad()
allCharacters = [Character(name: "All"),Character(name: "Luke Skywalker"),Character(name: "Leia Organa"),Character(name: "Advik Shah"),Character(name: "Aarav Modi")]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allCharacters.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
if cell == nil{
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell")
}
cell?.textLabel?.text = allCharacters[indexPath.row].name
if allCharacters[indexPath.row].isSelected
{
cell?.accessoryType = .checkmark
}
else
{
cell?.accessoryType = .none
}
cell?.selectionStyle = .none
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0
{
allCharacters[indexPath.row].isSelected = !allCharacters[indexPath.row].isSelected
for index in allCharacters.indices
{
allCharacters[index].isSelected = allCharacters[indexPath.row].isSelected
}
}
else
{
allCharacters[indexPath.row].isSelected = !allCharacters[indexPath.row].isSelected
if allCharacters.dropFirst().filter({ $0.isSelected }).count == allCharacters.dropFirst().count
{
allCharacters[0].isSelected = true
}
else
{
allCharacters[0].isSelected = false
}
}
tableView.reloadData()
}
}
struct Character
{
var name:String
// var otherDetails
var isSelected:Bool! = false
init(name:String) {
self.name = name
}
}
Creating Array of Struct objects from array of dictionary
let SubjectArray = json["students"] as! [[String:Any]]
allCharacters = SubjectArray.map({ Character(name: $0["studentName"] as! String) })
allCharacters.insert(Character(name:"All"), at: 0)
I like #Pranil's suggestion of using a separate section for the "All" row, so I have stolen that.
You can use an NSMutableIndexSet for tracking the selected rows. This is simpler than having to create a new struct or array of booleans or something. The only thing you do need to be aware of is if your tableview allows row reordering then the index set needs to be adjusted accordingly.
Here is my implementation. The "all" state is determined by the number of selected rows being equal to the number of rows in the data source array.
I have just used simple table view accessories for the checkmarks, but I am sure you can see how to adopt your image based approach in cellForRow(at:)
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableview: UITableView!
let names: [String]? = ["Luke Skywalker","Leia Organa","Advik Shah","Aarav Modi"]
var selectedRows = NSMutableIndexSet()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let names = self.names else {
return 0
}
return 0 == section ? 1 : names.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
var text: String
var accessory = UITableViewCellAccessoryType.none
if 0 == indexPath.section {
text = "All"
if self.selectedRows.count == self.names!.count {
accessory = .checkmark
}
} else {
text = names![indexPath.row]
if selectedRows.contains(indexPath.row) {
accessory = .checkmark
}
}
cell.textLabel!.text = text
cell.accessoryType = accessory
return cell
}
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
if indexPath.section == 0 {
if self.selectedRows.count == self.names!.count {
self.selectedRows = NSMutableIndexSet()
} else {
self.selectedRows = NSMutableIndexSet(indexesIn: NSRange(location: 0, length: self.names!.count))
}
tableView.reloadData()
} else {
self.selectedRows.contains(indexPath.row) ? self.selectedRows.remove(indexPath.row) : self.selectedRows.add(indexPath.row)
let rows = [IndexPath(row: 0, section: 0), indexPath]
tableView.reloadRows(at: rows, with: .none)
}
return nil
}
}
I think you are using only one section in the table view. I suggest you use two sections in the table view, so that first section will contain only one row (Select All) and the second section will contain other options. When you click on Select All, that is in the first row of the first section you can make all the rows in the second section as selected while reloading the table view.
// MARK: - struct for cell item
struct CellItem {
var name : String
var isSelected:Bool! = false
init(name: String) {
self.name = name
}
}
class ViewController: UITableViewController {
#IBOutlet var viewTable: UITableView!
// Declare a boolean varaible to toggle the checkbox in the first section of table view
var isSelectAllSelected : Bool = false
var cellData: [CellItem] = []
override func viewDidLoad() {
super.viewDidLoad()
cellData = [CellItem(name: "Luke Skywalker"),CellItem(name: "Leia Organa"),CellItem(name: "Advik Shah"),CellItem(name: "Aarav Modi")]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 1
}
else
{
return cellData.count
}
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0
}
// MARK: - Table view delegates
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = TableCell()
cell.selectionStyle = .none
if indexPath.section == 0 {
cell.textLabel?.text = "Select All"
if isSelectAllSelected{
cell.accessoryType = .checkmark
}
else{
cell.accessoryType = .none
}
}
else
{
cell.textLabel?.text = cellData[indexPath.row].name
if cellData[indexPath.row].isSelected{
cell.accessoryType = .checkmark
}
else{
cell.accessoryType = .none
}
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0
{
cellData[indexPath.row].isSelected = !cellData[indexPath.row].isSelected
isSelectAllSelected = cellData[indexPath.row].isSelected
for index in cellData.indices
{
cellData[index].isSelected = cellData[indexPath.row].isSelected
}
}
else
{
cellData[indexPath.row].isSelected = !cellData[indexPath.row].isSelected
if cellData.filter({ $0.isSelected }).count == cellData.count
{
isSelectAllSelected = true
}
else
{
isSelectAllSelected = false
}
}
viewTable.reloadData()
} }
Hello u can take cheboxbutton action method inside view controller with addtarget method and assign tag indexpath.row so u can easily get the indexpath. from below code u can get the idea.
class ViewController:UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var ObjTableview: UITableView!
var arrStudent = ["1","2","3","4","5"]
var arrSelectedStudent :[Int] = []
var selectAll:Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrStudent.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// create a new cell if needed or reuse an old one
let cell = ObjTableview.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SelectUserCell
// set the text from the data model
cell.selectionStyle = UITableViewCellSelectionStyle.none
// cell.lblStudentName.text = getStudentName[indexPath.row]
cell.lblStudentName.text = arrStudent[indexPath.row]
cell.btnCheckbox.tag = indexPath.row
cell.btnCheckbox.addTarget(self, action:#selector(btnCheckBoxClick(sender:)), for: .touchUpInside)
if selectAll {
cell.btnCheckbox.setImage(UIImage(named: "selectedItem"), for: .normal)
}else{
if arrSelectedStudent.contains(indexPath.row){
cell.btnCheckbox.setImage(UIImage(named: "selectedItem"), for: .normal)
}else{
cell.btnCheckbox.setImage(UIImage(named: "unSelectedItem"), for: .normal)
}
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
func btnCheckBoxClick(sender: UIButton) {
if sender.tag == 0{
selectAll = true
}else
{
selectAll = false
if let index = arrSelectedStudent.index(of: sender.tag) {
arrSelectedStudent.remove(at: index)
}else{
arrSelectedStudent.append(sender.tag)
}
}
ObjTableview.reloadData()
}}

Ordering TableViews by latest time

Currently I am having trouble ordering my table views in the right order. As of right now, they don't change order no matter what. I'm not sure what to add to fix this.
import UIKit
class ListNotesTableViewController: UITableViewController {
var notes = [Note](){
didSet{
tableView.reloadData();
}
}
override func viewDidLoad() {
super.viewDidLoad()
notes = CoreDataHelper.retrieveNotes()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return notes.count;
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath : IndexPath) ->ListNotesTableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "listNotesTableViewCell", for: indexPath) as! ListNotesTableViewCell
let row = indexPath.row
let note = notes[row]
cell.noteTitleLabel.text = note.title
cell.notePreview.text = note.content;
cell.noteModificationTimeLabel.text = note.modificationTime?.convertToString()
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier {
if identifier == "displayNote" {
print("Table view cell tapped")
let indexPath = tableView.indexPathForSelectedRow!
let note = notes[indexPath.row]
let displayNoteViewController = segue.destination as! DisplayNoteViewController
displayNoteViewController.note = note
} else if identifier == "addNote" {
print("+ button tapped")
}
}
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
CoreDataHelper.delete(note: notes[indexPath.row])
notes = CoreDataHelper.retrieveNotes()
}
}
#IBAction func unwindToListNotesViewController(_ segue: UIStoryboardSegue){
self.notes = CoreDataHelper.retrieveNotes()
}
}
It seems like your notes is not sorted by time. Whenever you get self.notes = CoreDataHelper.retrieveNotes() you need to sort your array. You can do it like this:
self.notes.sorted(by: { $0.date < $1.date })
Note that the date variable can differ depending on what variable name you have for your time and structure on your Note class.

Resources