Change checked status of selected cell from uiTableViewCell - swift

I'm new to swift and trying to change selected tableviewcell checked.
I'm trying to; user select city and districts and click to save button and app send the informations to server. There is no problem so there. When user wants to update the city or districts, I should check before districts and user can see what is he/she select or not. I'm getting first informations from server with json and append them to array. When user click the update button I can see before selected informations in debug mode but tableview cells are not going to be as checked. Sorry for my bad English btw.
What am I doing for first time selection :
in viewDidLoad()
self.tableViewDistrict.isEditing = true
self.tableViewDistrict.allowsMultipleSelection = true
self.tableViewDistrict.allowsMultipleSelectionDuringEditing = true
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectDeselectCell(tableView: tableView, indexPath: indexPath)
}
extension ViewController{
func selectDeselectCell(tableView: UITableView, indexPath: IndexPath){
self.selectedDistId.removeAll()
if let array = tableView.indexPathsForSelectedRows{
for index in array{
selectedDistId.append(districtArray[index.row].id!)
}
}
}
}

Lets suppose you have stored all your previous selected data inside an array like
var alreadySelectedDistricts : [String] = []
so in your cellForRowAt method you can do a check like
for district in alreadySelectedDistricts {
if cell.districtLabel.text.contains(district) {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
}

Related

Reusable UITableView for Varying Data Input - Swift/Xcode

I have a TableView that I want to reuse for different categories of data (essentially as plugins.. the tableView being a skeleton and being filled with whatever I want it to be). The TableView is filled with different categories of data (and related actions) depending on essentially what ViewController the user came from. I understand how to make it display the various data (just send it whatever array I want it to display), but I can't figure out how I could control the actions for the data at the specific index selected in didSelectRowAtIndexPath.
How could I do this? How could I create an array that has both Strings and executable actions associated with each indices? For example:
arrayOneNames = ["Tigris", "Leo", "Barko"]
arrayOneActions = [displayTheTigers, displayTheCats, displayTheDogs]
If "Leo" is selected in the tableView, then "displayTheCats" is executed. Again, I want each array to be a separate Class that I can use as a plugin, so that I can fill the tableView with whichever Class of data I want it to display and execute, depending on which ViewController the user came from previously. Please answer in Swift.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell=UITableViewCell() // cell you've created
cell.data = arrayOneNames[indexPath.row] // passing relevant data
cell.tag = indexPath.row // the tag you want to pass for particular data
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)! as UITableViewCell // take selected cell
if(cell.tag == 0) { // call relevant function accordingly.
self.tigrisTouch()
} else if (cell.tag == 1) {
self.leoTouch()
} else {
self.barkoTouch()
}
}
private func tigrisTouch() {
}
private func leoTouch() {
}
private func barkoTouch() {
}

Better performance events inside TableView cell

I am developing a Facebook like application, where if the post is too long, it gets cut down and at the end of it "See more" appears that has some click events. (I use FRHyperLabel for it)
Everything works fine, but I've got a question: If the formatting+event is decleared inside tableView: cellForRowAt indexPath: is it bad for the performance?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var message : message
var cell : MessageCell
let message = self.messages[indexPath.row]
// World Message
cell = tableView.dequeueReusableCell(withIdentifier: "essageCell", for: indexPath) as! MessageCell
cell.messageLabel.attributedText = message.limitMessageMax250char()
//Add link if needed
if message.count > appSettings.maxCharacters.message {
let handler = {
(hyperLabel: FRHyperLabel!, range: NSRange!) -> Void in
self.alert(title: "Test", message: "Alert: because clicked on link")
}
let text = cell.messageLabel.text!
let nsRange = text.calculateUnicodeScalar(start: text.unicodeScalars.count-8, len: 8) // See more is 8 characters
cell.messageLabel.setLinkFor(nsRange, withLinkHandler: handler)
}
return cell
}
Or should I do it in the Cell's file, when it's awakeFromNib + with delegate
IMO you don't want to do this in the for cellForRowAt call mostly because you want to make that call return quickly and also because you are only returning the formatted cell.
I would argue/recommend that you set your handler for the row when it is being initialized and that way the handler value is only being set once.
Remember that cellForRowAt is called multiple times as the user scrolls through and as cells come into view.
review the https://developer.apple.com/documentation/uikit/uitableviewdatasource/1614861-tableview for more information as to how cells are reused.

Swift 4 SegmenterControl with TableView

I build a social app, now I want to make some good appearance. I want to change tabs Contacts / Rooms from segmentedCntrol. How can I do that with correct form? I have two ways...Clear contacts table view and fill it with Rooms data. Or hide view with a table view and display another view with new tableView.
You should create 2 tableViewCells and switch between them in cellForRowAt according to selected segment
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if mySegment.selectedSegmentIndex == 0
{
let cell = tableView.dequeueReusableCell(withIdentifier:CellIdentifier1) as! Cell1
// setup here
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier:CellIdentifier2) as! Cell2
// setup here
}
}

Index out of range for indexPath swift

I am making an app that requires the user to tap on multiple cells in order to select them. when they tap on a cell, a .Checkmark accessory item will appear. For some reason though whenever I try and get to that VC the app crashes and I get the following error messages on line 8(if !checked[indexPath.row]):
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell: InstrumentTableCell! = tableView.dequeueReusableCellWithIdentifier(identifier) as? InstrumentTableCell
cell.configurateTheCell(recipies[indexPath.row])
if !checked[indexPath.row] {
cell.accessoryType = .None
} else if checked[indexPath.row] {
cell.accessoryType = .Checkmark
}
return cell
}
and this is my working checked method:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
if cell.accessoryType == .Checkmark {
cell.accessoryType = .None
checked[indexPath.row] = false
} else {
cell.accessoryType = .Checkmark
checked[indexPath.row] = true
}
}
}
Your problem is that you only store items in your checked array when tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) is called. However, that method is only called when you actually select a row.
tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) on the other hand is called each and every time you need to render a new table cell.
So when you in cellForRowAtIndexPath asks:
if !checked[indexPath.row]
then you can not be sure that checked actually contains anything. For instance the first time you start rendering your cells, your checked array does not contain any values and therefore it crashes when you ask it for a value on a position that it does not have a value for.
One solution could be to initialize your checked array to contain all false values. I'm guessing you have some model array called recipies so you could do something like:
for (index, _) in recipies.enumerate() {
checked.append(false)
}
Or as #AaronBrager suggests in the comments below (which is way prettier :))
checked = Array(count:recipies.count, repeatedValue:false)
that way you are sure that your checked array is properly initialized with the same number of elements as you have recipies.
Another option could be to let the individual elements in recipies know whether or not they are checked.
Hope this makes sense and helps you.

TableView on simulator is not referencing correctly

Hello and how is everyone?
When I run the simulation of my application I go to select the first object in the table. Nothing happens. I then go and select the second object and it performs the action that the first object was supposed to. Basically the first object is not active until I select it and then select another object.
Maybe this will help:
I turn the simulator on. I select the first object nothing happens(I have a print("what row I selected") within the didSelect function to make sure it is working.). But again no printout until I hit the second object, the second object should print #1 row selected but it says #0 row selected and then performs the segue setup for 0#. After I come back from the segue the first object still performs the same.
Here is my tableView Code:
var objects: NSMutableArray! = NSMutableArray()
override func viewDidLoad() {
super.viewDidLoad()
self.objects.addObject("help")
self.objects.addObject("me")
self.objects.addObject("please")
self.objects.addObject("thankyou")
self.tableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(self.objects.count)
return self.objects.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableViewCell
cell.titleLabel.text = self.objects.objectAtIndex(indexPath.row) as? String
return cell
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.row)!")
Thanks for the help.