selectrow at index for different sections - ios

I have a table with two sections. I can select row at index - but I cannot differentiate between the sections.
the table is a pullout menu - which is created solely in code.
the delegate method for the selection is
func sideBarControlDidSelectRow(indexPath: NSIndexPath) {
delegate?.sideBarDidSelectButtonAtIndex(indexPath.row)
sectionis = indexPath.section
NSLog("Index Path Section %d", indexPath.section)
}
this gives me the section in the console.
but on the view controller all I have is
func sideBarDidSelectButtonAtIndex(index: Int){
switch(index) {
etc.
}
}
What I need to be able to do is something like
func sideBarDidSelectButtonAtIndex(index: Int){
if section == 0 {
switch(index){
etc.
}
}
}
but if I try that then Binary operator cannot be applied to operands of type section
this has got to be something obvious as tables have sections all the time - but the answer is eluding me.

Just update declaration of method sideBarDidSelectButtonAtIndex in delegate protocol to accept NSIndexPath value, change:
func sideBarDidSelectButtonAtIndex(index: Int)
to
func sideBarDidSelectButtonAtIndex(indexPath: NSIndexPath)
then you can just remove this method
func sideBarControlDidSelectRow(indexPath: NSIndexPath) {
delegate?.sideBarDidSelectButtonAtIndex(indexPath.row)
}
and replace its call just with
delegate?.sideBarDidSelectButtonAtIndex(indexPath)
Then you'll receive full indexPath and could do what you want

Related

How can I get the index path.row of first UITableView in the Second UITableView using Swift3

I have two UITableViews. The first UITableView contains an array of data, and the second is empty. How can I get the index path of the first table to use it in the second table to view different data? This is an example of what I want to do in the second table:
This is in the second table and like this function where I want to get the indexPath.row of first table.
func loadData() {
if indexPath.row == 0 { // (of first table)
// add code
} else if indexPath.row == 1 { // (of first table)
// add code
}
}
Implement didSelectRowAt
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let selctedIndex = indexPath.row
self.setIndexToSecondTableView(selctedIndex) //Create your function to get selected index of first table view
}
Hope You get solution.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if tableView.isEqual(firstTableView) {
self.updateScecondTableView(index: IndexPath.row) //make a function to retrieve selected index from first table view
} else {
// acode
}
}
func updateScecondTableView(index:NSIndexPath) {
switch index.row {
case 0:
// add a code
break
default:
// add a code
break
}
}

Best way to populate rows in section in UITableView?

I'm building an app, where I got several sections in an UITableView. My current solution is collecting my data in a dictionary, and then pick one key for every section. Is there a better solution?
One of the good ways to it - direct model mapping, especially good with swift enums.
For example you have 2 different sections with 3 different type of rows. Your enum and ViewController code will look like:
enum TableViewSectionTypes {
case SectionOne
case SectionTwo
}
enum TableViewRowTypes {
case RawTypeOne
case RawTypeTwo
case RawTypeThreeWithAssociatedModel(ModelForRowTypeNumberThree)
}
struct ModelForRowTypeNumberThree {
let paramOne: String
let paramTwo: UIImage
let paramThree: String
let paramFour: NSData
}
struct TableViewSection {
let type: TableViewSectionTypes
let raws: [TableViewRowTypes]
}
class ViewController: UIViewController, UITableViewDataSource {
var sections = [TableViewSection]()
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].raws.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let raw = sections[indexPath.section].raws[indexPath.row]
switch raw {
case .RawTypeOne:
// Here return cell of first type
case .RawTypeTwo:
// There return cell of second type
case .RawTypeThreeWithAssociatedModel(let modelForRawTypeThree):
// And finally here you can use your model and bind it to your cell and return it
}
}
}
What benefits? Strong typization, explicit modelling, and explicit handling of your various cell types. The only simple thing that you have to do in that scenario it is parse your data into this enums and structs, as well as you do it for your dictionaries.
Here is a quick example that I wrote. Please note, it error-prone since it is not checking wether the keys exists not does it create a proper cell.
You could do this with a dictionary as well, since you can iterate over its content.
Hope it helps:
class AwesomeTable: UITableViewController {
private var tableContent: [[String]] = [["Section 1, row 1", "Section 1, row 2"], ["Section 2, row 1", "Section 2, row 2"]]
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return tableContent.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableContent[section].count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath)
let item = tableContent[indexPath.section][indexPath.row]
cell.textLabel?.text = item
return cell
}
}
Implement the table view datasource as follows:-
1) Set number of sections = no of keys in dictionary
2) No of rows in section = no of values in dictionary at index(section)

SegmentedControl hide and show TableView cells

I'm working on an exercise application where the user is able to do use a UISwitch to set if a exercise is active or not. I have a segmented controller that is used to switch to show "All" or only to show "Active".
Is it possible to get the specific cells with this property within my UISegmentedControl Action?
My code looks like this:
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier("ChallengeCell") as? ChallengeListCell {
cell.setTitle("Utmaning " + String(indexPath.row + 1))
let active = indexPath.row % 3 == 0 || indexPath.row % 5 == 0
cell.setActive(active)
if active {
cell.setCompleted((Double(indexPath.row % 5) + Double(indexPath.row % 3)) / 6.0)
}
else {
cell.setCompleted(0)
}
return cell
}
return UITableViewCell()
}
and my SegmentedControl function looks like this:
#IBAction func segmentedControlChanged(sender: UISegmentedControl) {
let selectedSegment = segmentedControl!.selectedSegmentIndex
switch selectedSegment{
case 0: //SHOW ALL
print("Selected 0")
case 1: //SHOW ONLY ACTIVE
print("Selected 1")
//case 2: //NOT ACTIVE
//print("Selected 2")
default:
print(sender)
}
}
All of this is in the same Controller.
You should have three datasource arrays: for example allItems activeItems and inactiveItems, and switch between them.
Inside the tableView delegates check the segment selected with the segmentedControl and use the right array as datasource.
Inside segmentedControlChanged call self.tableView.reloadData() and set a variable with the selected segment.
One way would be to keep track of the index paths of "Active" cells in an array that's an instance property of your view controller. Than when the segmented controller is toggled, you can determine what cells to remove/add from the table view just by looking at the array.
Another idea would be to have an active property on the model objects that hold the data for each table view cell. When the segmented control is toggled, you can iterate over all of these objects to determine if they're "Active" or not and proceed accordingly.
From your code provided, it sounds like my first suggestion would be most appropriate.

SWIFT - UITableViewCell updating based on selection

I have a TableViewController (lets call TVC1) with a row that says "OD" (which stands for Outer Diameter).
Upon selecting this row, a bunch of rows in a new TableViewController (lets call TVC2) containing the various OD (casingOD in my code) shows. What I want to happen is when the user selects the OD it will segue back to the main TableViewController with the string that corresponds to the user selection. My code for this currently fails...Could anyone help point me in the right direction? If you require TVC1 code i'll happily post it, i'm just trying to save any unneccessary code reading for you folks :)
My TVC2 code is as follows:
import UIKit
class CasingSelectionTableViewController: UITableViewController {
var selectedData: Data?
let casingOD = ["114.3", "127.0", "139.7", "168.3" , "177.8", "193.7", "219.1", "244.5", "247.6", "273.1", "298.4", "298.4", "339.7", "406.4", "473.0", "508"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
switch selectedData! {
case .OuterDiameter:
print(casingOD)
case .Weight:
print(casingWeight114) // I deleted the casingWeight114 line of code as its not required for this question
case .InnerDiameter:
print(id114) // I deleted the id114 line as its not required for this question
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return casingOD.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var casingSpec: UITableViewCell!
if selectedData == Data.OuterDiameter {
casingSpec = tableView.dequeueReusableCellWithIdentifier("selectedCasingSpec", forIndexPath: indexPath)
let casingODSpec = casingOD[indexPath.row]
casingSpec.textLabel?.text = casingODSpec
return casingSpec
} else {
return casingSpec
}
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selection: UITableViewCell!
selection.textLabel?.text = indexPath.row as! String
}
What I want to happen is when the user selects the OD it will segue back to the main TableViewController with the string that corresponds to the user selection.
First of all you'll need to implement a way for TVC2 to notify TVC1 that a value has been selected.
A common way to do such thing is by using delegation. You can define a delegate protocol like this:
protocol TVC2Delegate {
func tvc2(tvc2: TVC2, didSelectOuterDiameter outerDiameter: String)
}
Then add a var delegate: TVC2Delegate? property to TVC2.
You'll then make TVC1 comform to TVC2Delegate by implementing that method in TVC1.
When presenting TVC2 from TVC1 remember to set it as the delegate for TVC2.
// In TVC1
tvc2.delegate = self
To connect TVC1 and TVC2 you could add a bit o logic to your tableView(tableView:,didSelectRowAtIndexPath:) method call the delegate with the selected value
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let stringValue = indexPath.row as! String
// Do anything you need to do related to TVC2 here.
// Then finally
delegate?.tvc2(self, didSelectOuterDiameter: stringValue)
}
Finally, in TVC1's implementation of the delegate method you can take care of dismissing TVC2 if needed.
Update:
This is how the final implementation of these bits might look like:
// In TVC1
class TVC1: UITableViewController, TVC2Delegate {
// ...
// Implement the method(s) of TVC2Delegate
func tvc2(tvc2: TVC2, didSelectOuterDiameter outerDiameter: String) {
// Do whatever you need to do with the outerDiameter parameter
}
}
// In TVC2
protocol TVC2Delegate {
func tvc2(tvc2: TVC2, didSelectOuterDiameter outerDiameter: String)
}
class CasingSelectionTableViewController: UITableViewController {
var delegate: TVC2Delegate?
// ...
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let stringValue = casingOD[indexPath.row]
// Do anything you need to do related to TVC2 here.
// Then finally
delegate?.tvc2(self, didSelectOuterDiameter: stringValue)
}
}
Use the delegate approach as suggested in the answer by #Mokagio. And in case you're having issue in getting the string, here is the answer
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! UITableViewCell
let stringValue = cell.textLabel.text //You can get this from your datasource as well)
//call the delegate
}

Inserting rows in UITableView upon click

I'm having trouble adding rows to the UITableView upon UIButton click.
I have two custom-cell xibs - one that contains an UILabel, another one that contains an UIButton.
Data for the table cell is loaded from two dictionaries (answersmain and linesmain).
Here is the code for the UITableView main functions:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.linesmain["Audi"]!.count + 1
}
// 3
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if(indexPath.row < 3){
var cell:TblCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! TblCell
cell.lblCarName.text = linesmain["Audi"]![indexPath.row]
return cell
} else {
var celle:vwAnswers = self.tableView.dequeueReusableCellWithIdentifier("cell2") as! vwAnswers
celle.Answer.setTitle(answersmain["Good car"]![0], forState:UIControlState.Normal)
return celle
}}
What do I put here?
#IBAction func option1(sender: UIButton) {
// I need to add rows to the uitableview from two dictionaries into two different xibs
}
You can do the next:
var showingAll = false
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return showingAll ? self.linesmain["Audi"]!.count + 1 : 0
}
#IBAction func option1(sender: UIButton) {
showingAll = true
tableView.beginUpdates()
let insertedIndexPathRange = 0..<self.linesmain["Audi"]!.count + 1
var insertedIndexPaths = insertedIndexPathRange.map { NSIndexPath(forRow: $0, inSection: 0) }
tableView.insertRowsAtIndexPaths(insertedIndexPaths, withRowAnimation: .Fade)
tableView.endUpdates()
}
You should take a look over the documentation here
There is this UITableView method called insertRowsAtIndexPaths:withRowAnimation: that inserts row at a specified indexPath.
You need to modify linesmain and answersmain by adding data to these and then call [self.tableView reloadData].
It would be better if you extract linesmain["Audi"] and answersmain["Good car"] and save them into different mutable arrays and modify those.
You need to do this in the func option1.

Resources