6

I have searched the internet countless times and have not found a solution to my situation. Things that may be a solution are things I didn't understand and they were in Objective-C. So if this is a duplicate, it isn't. I have failed to get a solution from other posts.

I am making a GPA Calculator specifically for my school where we get different points depending on our subject levels too.

I made a UITableView with a custom cell that will be duplicated specific amount of times each for each subject in the grade.

What I want to know is getting the data from each of these custom cells(the score and the level)

So this is my storyboard:

Storyboard

and this is my app previewed in the simulator:

App Screenshot

I'm going to get the score and the level by getting the text of the labels in each subjects and I have no idea how to get data from specific cells.

Thank you very much.

Here's the code i currently have:

//showStepperValueLabel shows the level and showSliderValueLabel shows the score in the cells.
//customCell is my custom class for my custom cell.
//i have already declared the levels and scores array above in my class

func tableView(tableView: UITableView!, didDeselectRowAtIndexPath indexPath: NSIndexPath!) {
    let cell = tableView.cellForRowAtIndexPath(indexPath) as customCell
    var level: String! = cell.showStepperValueLabel.text
    var score: String! = cell.showSliderValueLabel.text
    levels[indexPath.row] = level
    scores[indexPath.row] = score

}


//yadiyadayada 



//and this is the part where the values get received(it's inside the prepareForSegue function)

    var engScore: String = scores[0]
    var engLevel: String = levels[0]
    var mathScore: String = scores[1]
    var mathLevel: String = levels[1]
    var sciScore: String = scores[2]
    var sciLevel: String = levels[2]
    var geoScore: String = scores[3]
    var geoLevel: String = levels[3]
    var hisScore: String = scores[4]
    var hisLevel: String = levels[4]
    var chiScore: String = scores[5]
    var chiLevel: String = levels[5]
    //

But i'm getting an error where the arrays never received the values. can someone help?

EDIT:

i got an error again so i tried giving the strings manually to the arrays while its initialization like

var levels: [String] = ["H", "H", "H", "H", "H", "H"]
var scores: [String] = ["12", "23", "34", "45", "56", "67"]

and the program worked perfectly fine. So that concludes that the problem occurs in the part where the array receives the strings which is

func tableView(tableView: UITableView!, didDeselectRowAtIndexPath indexPath: NSIndexPath!) {
    let cell = tableView.cellForRowAtIndexPath(indexPath) as customCell
    var level: String! = cell.showStepperValueLabel.text
    var score: String! = cell.showSliderValueLabel.text
    levels.insert(level, atIndex: indexPath.row)
    scores.insert(level, atIndex: indexPath.row)

}

are you sure the disselect thing is the correct way? everyone else in the internet taught me to use tags however didn't tell me how to use it...

EDIT2:

so i tried using tags. this is what i wrote in the tableView: cellForRowAtIndexPath function

cell.showStepperValueLabel.tag = indexPath.row+10
cell.showSliderValueLabel.tag = indexPath.row

and this is what i wrote in the prepareForSegue

var engScore : UILabel! = self.view.viewWithTag(0) as? UILabel
    var mathScore: UILabel! = self.view.viewWithTag(1) as? UILabel
    var sciScore: UILabel! = self.view.viewWithTag(2) as? UILabel
    var geoScore: UILabel! = self.view.viewWithTag(3) as? UILabel
    var hisScore: UILabel! = self.view.viewWithTag(4) as? UILabel
    var chiScore: UILabel! = self.view.viewWithTag(5) as? UILabel

    var engLevel: UILabel! = self.view.viewWithTag(10) as? UILabel
    var mathLevel: UILabel! = self.view.viewWithTag(11) as? UILabel
    var sciLevel: UILabel! = self.view.viewWithTag(12) as? UILabel
    var geoLevel: UILabel! = self.view.viewWithTag(13) as? UILabel
    var hisLevel: UILabel! = self.view.viewWithTag(14) as? UILabel
    var chiLevel: UILabel! = self.view.viewWithTag(15) as? UILabel

so in the functions of calculating GPA i put

//Get pxcs
    engpxc = engCredits*co.getEnglishPoints(engLevel.text!, engScore: engScore.text!)
    mathpxc = mathCredits*co.getNonLanguagePoints(mathLevel.text!, scoreRecieved: mathScore.text!)
    geopxc = geoCredits*co.getNonLanguagePoints(geoLevel.text!, scoreRecieved: geoScore.text!)
    hispxc = hisCredits*co.getNonLanguagePoints(hisLevel.text!, scoreRecieved: hisScore.text!)
    scipxc = sciCredits*co.getNonLanguagePoints(sciLevel.text!, scoreRecieved: sciScore.text!)
    chipxc = chiCredits*co.getChiPoints(chiLevel.text!, chiScore: chiScore.text!)
    //

and now i'm getting an error that says

fatal error: unexpectedly found nil while unwrapping an Optional value (lldb)

can someone help me with this?

EDIT3 - more info:

i added println in the tableView: cellForRowAtIndexPath function in parts where i give the tags and found out that the tags were given successfully and those labels received the tags i assigned in the program however when i checked with println in the prepareForSegue function in where the variables receive their views to see if they received the labels successfully but i got 'nil' there. What in the world is the problem?

Chan Woo
  • 139
  • 1
  • 1
  • 10
  • I checked your edit and I think you're going wrong in the way you assign values to your array's indices. Firstly, your _levels_ array should be of type `NSMutableArray`. Then your assignment statement should change to: `levels.insertObject(level, atIndex: indexPath.row)` – Lester Feb 17 '15 at 06:50
  • aren'y NSMutableArray for assigning objects in an array?? level and score are of type String and im trying to store them to an array so that they can recieve the data in the below – Chan Woo Feb 17 '15 at 16:33
  • i'm getting an error of 'AnyObject' is not convertible to 'String' – Chan Woo Feb 17 '15 at 16:35
  • i'll need to see more of your code to help you with your error. – Lester Feb 18 '15 at 04:57
  • You're right, `NSMutableArray` is for assigning objects and even your `String` type here is an object that you need to insert into your array. If you're still unsure about using `NSMutableArray`, and are certain your level and score are of type `String`, then see my edit in the answer section. Try to declare your array in the same way that I have, and follow how I have assigned the level and score `String` objects to their respective arrays. – Lester Feb 18 '15 at 05:07
  • Did you get any solutions ??? – Neha May 09 '17 at 00:47

3 Answers3

12

First retrieve your cell where you need it (for instance in didSelectRowAtIndexPath). Cast your UITableViewCell in your custom cell. And then access properties of your cell as you wish.

Since you haven't provided any code, I will provide simply examples of the code:

func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
    let cell = tableView.cellForRowAtIndexPath(indexPath) as YourCell
    //cell.value, cell.text, cell.randomValue or whatever you need
}

What about submit button, you want to submit the data right? And you don't have indexPath there...

Well you have several options, one is to go through each cell, check the type and get it. But seems like your each cell is different one. And seems like you have order for these cells. So you know where exactly your result will be. So, in submit you can do the following

@IBAction func submit_pressed(sender: UIButton) {
     var indexs = NSIndexPath.init(index: 10)
     // or which one(s) you need. you extract data from the cell similar to previous function
}

But, why do you have to get entire cell to get one value? How about you create few variables (or even better, array) and extract values there? you can link events to these controls and when they change you get these value and save them. Later on, you can use these values(or array) without accessing cells or retrieving them.

EDIT:

How about tags? I am not sure if you are adding this through code or storyboard, but I will go through both of them.

In cellForRowAtIndexPath, you can simply say cell.tag = indexPath.row, or even better: cell.tag = question.id ( assuming that question is your custom class). That way, you can go through questions and take specific ones.

Here is working code with tags:

    @IBAction func test(sender: AnyObject) {
        var lbl : UILabel = self.tableView.viewWithTag(12) as UILabel!
        var cell : UITableViewCell = self.view.viewWithTag(3) as UITableViewCell!
        return ;
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = indexPath.row == 0 ? tableView.dequeueReusableCellWithIdentifier("firstCell", forIndexPath: indexPath) as UITableViewCell : tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as UITableViewCell
        if(indexPath.row != 0){
        let item = toDoList[indexPath.row-1]

        cell.textLabel?.text = item.title
        NSLog("%d",indexPath.row)
        var integerncina = (indexPath.row + 10) as NSInteger!
        cell.textLabel?.tag = integerncina
        NSLog("%d", cell.textLabel!.tag)
        cell.tag = indexPath.row
        }
        // Configure the cell...

        return cell
    }
Miknash
  • 7,888
  • 3
  • 34
  • 46
  • No the thing is I have one custom cell and it is going to be duplicated in my UITableView. Each custom cell represents a subject. So if i have a cell that's going to be duplicated, how do i get the score and the level the user chose from EACH of these cells??? That's the problem I'm currently having. Retrieving user inputs from each of the cells that I don't know how to have a control over. – Chan Woo Feb 11 '15 at 14:59
  • Edited, Hope it helps – Miknash Feb 11 '15 at 15:13
  • i actually heard of the solution using tags but I still havent an idea how to use it. I'm really sorry i' m a newbie in ios development. but after i tag those labels, where exactly do i write the code where i take the text of the labels(the user inputs) and give it to some variable? – Chan Woo Feb 11 '15 at 15:26
  • Okay, in your submit, you can go through questions and look for cells with tag: `YourCell *cell = (YourCell*)[tableView viewWithTag:question.id];` and after you can do something like `cell.textfield.text`. Another solution could be ( if you have your own class for the prototype cell) is to add `NSInteger questionId;` to its definition and then use it as as `cell.questionId = question.id`. Later on, you can go through your cells and check for each cell and get corresponding answer/selected value. – Miknash Feb 11 '15 at 15:35
  • the question.id thing isnt working. Are you sure this is swift because isn't that in obj-C? – Chan Woo Feb 14 '15 at 06:39
  • can you tell me how to utilize tags for a solution? – Chan Woo Feb 14 '15 at 06:49
  • I assumed that you have id in your question object. If that's the case, you can say something like YourCell *cell = (YourCell*)tableView.viewWithTag:question.id]; If you don't you should add for countless number of reasons – Miknash Feb 14 '15 at 10:19
  • can you check my edit2 and tell me where i went wrong? – Chan Woo Feb 18 '15 at 12:01
  • Do you get this error for particular label or for first one ? Also can you check that your labels are not actually nil at getting them via tag? – Miknash Feb 18 '15 at 12:09
  • I have posted the working code into my answer, seems like everything is ok, have you changed the rest of your cellAtIndexPath function? – Miknash Feb 18 '15 at 12:56
  • i wrote "var engScore : UILabel = self.tableView.viewWithTag(12) as UILabel!" but i got an error saying '(UITableView, numberOfRowsInSection: Int) -> Int' does not have a member named 'viewWithTag' – Chan Woo Feb 18 '15 at 13:05
  • If you don't have tableView ( I tested this on TableViewController ) try with view... Can you send me over your project, I will find your issue easier. My email is namik.catibusic@gmail.com – Miknash Feb 18 '15 at 13:15
  • You are missing reference from storyboard for table view. After I added it it was working fine. Although this will fix your bug, I highly suggest going through cells, and try to get wanted results that way. That way, you could use only one VC for all the tests. – Miknash Feb 18 '15 at 13:37
  • im still getting and error and the only information im getting is (llbd)...... what do i do – Chan Woo Feb 19 '15 at 03:32
  • I don't know how that doesn't work, I will check today and find your issue, and therefore, reply to your email with solution – Miknash Feb 24 '15 at 12:48
  • @NickCatib: hi, in my iOS app I'm developing I have just arrived at this point, where in IBAction should collect all the data from all cells, create an object with them and store it. I'm making a lot of confusion so I would like to ask you a pair of questions: – SagittariusA Sep 10 '15 at 22:00
  • @NickCatib 1) I don't understand what the method func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) does. Is it used to get data from each cell? When is it called? (in other words how can I link it to the IBAction of the submit button) – SagittariusA Sep 10 '15 at 22:00
  • @NickCatib: 2) is it better to assign to each cell an unique tag to read the data when the submit button is touched? – SagittariusA Sep 10 '15 at 22:01
  • I will answer on these questions on your question : http://stackoverflow.com/questions/32506955/how-to-read-data-test-from-each-row-of-a-uitableview – Miknash Sep 11 '15 at 07:38
4

I know this is a very old post but then to if it helps someone I'll be happy so to do this the simple way which I will prefer is made an array of the UI table view cell and called it in the UI View Controller and then this becomes very simple just called the array (Thanks to rohan)

(FOR EXAMPLE)

import UIKit


public class PlanningTableView:UITableViewCell{

    @IBOutlet weak var Sccode: UITextField!
    @IBOutlet weak var NoOfPatients: UITextField!

}

(AND NOW IN VIEW CONTROLLER DO THIS)

import UIKit

class PlanningReport:UIViewController,UITableViewDelegate,UITableViewDataSource{

    var ScCode = [String]()
    var NoOfPatient = [String]()
    var CollectionOfCell = [PlanningTableView]()


 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! PlanningTableView
    CollectionOfCell.append(cell)
    return cell
}

//////// Then at sumbmit Button just do this /////////////////

@IBAction func Submit(_ sender: Any) {

     CollectionOfCell.forEach { cell in
           ScCode.append(cell.Sccode.text!)
           NoOfPatient.append(cell.NoOfPatients.text!)
     }
}

For more details I just created a YouTube first ever tutorial - comments good/bad appreciated

rsakhale
  • 1,018
  • 13
  • 26
kunal pal
  • 314
  • 2
  • 9
3

To collect data from your cells after the user has finished entering the data (score and level), you can use the UITableView delegate method tableView:didDeselectRowAtIndexPath[Deselect]

The code in your instance will go in UITableViewController class and will look something like this.

override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
    let cell = tableView.cellForRowAtIndexPath(indexPath) as YourCustomCellClass
    var levelArray:[String] = [] //Assuming you want to collect and store your cell data in an Array. You may use a Dictionary as well, whichever is more convenient.
    var scoreArray:[String] = []
    // levelArray.append(cell.levelLabel.text!)
    // scoreArray.append(cell.scoreLabel.text!)
    levelArray.insert(cell.levelLabel.text!, atIndex: indexPath.row)
    scoreArray.insert(cell.scoreLabel.text!, atIndex: indexPath.row)
}

Next, in you submit button's action(Selector) function use the 'levelArray' and 'scoreArray' to pass your collected data. Be sure to declare the array/dictionary variables(ex: levelArray) right under your UITableViewController class declaration, like so

class GpaCalculator: UITableViewController {
    var levelArray:[String] = []
    var scoreArray:[String] = []

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    // ...
}

..to be able to use it in other functions like your submit button's action(Selector) function.

Lester
  • 731
  • 11
  • 12
  • what does tableView:didDeselectRowAtIndexPath do? – Chan Woo Feb 14 '15 at 05:55
  • This method is called, in your case, when the user has finished editing the score & level on a particular cell, and touches outside the cell either to hit the submit button or to edit the next cell. Thereby, deselecting the edited cell and allowing you to store label data. Does that help? – Lester Feb 16 '15 at 11:27
  • can you check my edit and tell me what the problem is? – Chan Woo Feb 16 '15 at 11:49
  • can you check the comments i left in the question – Chan Woo Feb 18 '15 at 01:36
  • Yes, see the changes in the `tableView:didDeselectRowAtIndexPath` method. – Lester Feb 18 '15 at 10:32
  • why do i make the arrays again in the didDeselectRowAtIndexPath function?? i already decalred it in the top of the class. why again in the functioms? – Chan Woo Feb 18 '15 at 10:41
  • wait i thk i shouldve mentioned - im doing all this on my viewcontroller class i dont have a separate controller class for the tableview – Chan Woo Feb 18 '15 at 10:43
  • You do not have to make array in `tableView:didDeselectRowAtIndexPath` method. I'm only asking you to make array like I have. `var levelsArray: [String] = []` This basically means you are declaring an array that takes only `String` type objects. Got it? – Lester Feb 18 '15 at 11:08
  • And your view controller class approach is fine too. No changes required. – Lester Feb 18 '15 at 11:10
  • but it isn't working for some reason. Your approach requres the users to touch the cell and enter their scores and levels and move on right? but what if they dont even make a change in the cell and leave it like tht and press submit?? Because of these two reasons i tried a new approach using tags and its in EDIT2 up there in my question post and im having trouble with it. can you help me with that? – Chan Woo Feb 18 '15 at 12:02
  • Good point. I didn't take that scenario into consideration. My bad. – Lester Feb 19 '15 at 05:35