I am creating an app that I want to display different strings inside of a label that is within a UITableViewCell. However, I cannot use indexPath.row because the strings are in not particular order.
let one = "This is the first quote"
let two = "This is the second quote"
var numberOfRows = 1
var quoteNumber = 0
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let items = [one, two]
myTableView = tableView
let cell = tableView.dequeueReusableCellWithIdentifier("customcell", forIndexPath: indexPath) as! cellTableViewCell
let cellWidth = cell.frame.width
let cellHeight = cell.frame.height
cell.QuoteLabel.frame = CGRectMake(cellWidth/8, cellHeight/4, cellWidth/1.3, cellHeight/2)
let item = items[quoteNumber]
cell.QuoteLabel.text = item
cell.QuoteLabel.textColor = UIColor.blackColor()
if quoteNumber == 0 {
quoteNumber = 1
}
if numberOfRows == 1 {
numberOfRows = 2
}
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
var timer = NSTimer.scheduledTimerWithTimeInterval(5, target: self, selector: "update", userInfo: nil, repeats: true)
}
func update() {
dispatch_async(dispatch_get_main_queue()) {
self.myTableView.reloadData()
}
This code builds and runs, but when the timer I have set expires and the update function is ran, both of the two available cells change to the same label. What I am trying to do is make it so that the first cell can remain static while the newly added cell can receive the new element from the 'items' array without using indexpath.row (because the quotes that I am going to be using from the items array will be in no particular order). Any help would be appreciated.
Instead of reloadData try using reloadRowsAtIndexPaths: and pass in the rows you want to reload. This does use indexPath, however. The only way I'm aware of to reload specific rows as opposed to the whole tableView is to specify the rows by index path.
Related
I reached a correct value and printed it during the debug sessions. However, when i run the application, the calculated value (newcalory) doesn't show up the specific table cell text field. (aka. cell.itemTotalCalory.text) Do you have any ideas for the solution?
*I attached the related code blocks below.
Thanks a lot,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = ingredientTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! IngredientTableViewCell
cell.ingredientNameTextField.text = ingredients [indexPath.row].ingredientName
cell.numberofItem.text = "1"
let cellcalory = ingredients [indexPath.row].ingredientCalory
cell.itemTotalCalory.text = cellcalory
cell.plusButton.tag = Int(cell.itemTotalCalory.text!)! //indexPath.row
cell.plusButton.addTarget(self, action:#selector(plusAction), for: .touchUpInside)
cell.minusButton.tag = Int(cell.itemTotalCalory.text!)!
cell.minusButton.addTarget(self, action:#selector(minusAction), for: .touchUpInside)
return cell
}
#IBAction func plusAction(sender: UIButton)
{
let cell = ingredientTableView.dequeueReusableCell(withIdentifier: "cell") as! IngredientTableViewCell
let buttonRow = sender.tag
if cell.numberofItem.text == "1" || cell.numberofItem.text != "1"
{
cell.numberofItem.text = "1"
let textValue1 = cell.numberofItem.text
var textValue = Int(textValue1!)
textValue = textValue! + 1
cell.numberofItem.text = String(describing: textValue)
let oldcalory = buttonRow
cell.itemTotalCalory.text = String (((textValue! * Int(oldcalory)) + Int(oldcalory)))
let newcalory = cell.itemTotalCalory.text
refresh(newcalory: newcalory!);
}
}
func refresh(newcalory :String)
{
let cell = ingredientTableView.dequeueReusableCell(withIdentifier: "cell") as! IngredientTableViewCell
cell.itemTotalCalory.text = newcalory
DispatchQueue.main.async {
self.ingredientTableView.reloadData()
}
}
What you should do is to update the value in ingredients array and then call ingredientTableView.reloadData() to reflect this to the UI.
Calling dequeueReusableCell(withIdentifier:) in refresh method will not work as expected for what are you trying to do:
For performance reasons, a table view’s data source should generally
reuse UITableViewCell objects when it assigns cells to rows in its
tableView(_:cellForRowAt:) method. A table view maintains a queue or
list of UITableViewCell objects that the data source has marked for
reuse. Call this method from your data source object when asked to
provide a new cell for the table view. This method dequeues an
existing cell if one is available or creates a new one using the class
or nib file you previously registered. If no cell is available for
reuse and you did not register a class or nib file, this method
returns nil.
So, refresh method should be similar to:
func refresh() {
// updating ingredients array upon reqs satisfaction...
// and then:
ingredientTableView.reloadData()
// nameOfYourRefreshControl.endRefreshing()
}
Also, if you are pretty sure that you want to get a specific cell from the tableView, you might want to use cellForRow(at:) instance method:
Returns the table cell at the specified index path.
func refresh() {
let cell = ingredientTableView?.cellForRow(at: YOUR_INDEX_PATH)
//...
}
Hope this helped.
I found the solution, the lines that are listed below are useless.
let cell = ingredientTableView.dequeueReusableCell(withIdentifier: "cell") as! IngredientTableViewCell
cell.itemTotalCalory.text = newcalory
I updated the ingredient array with the new value inside the plusAction function and my problem solved. Thanks for all postings.
I have a label I want to tap on using addGestureRecognizer. I put it in cellForRowAtIndexPath but when I do print(label.text), it prints a label from another cell. But when I put it in didSelectRowAtIndexPath, it prints out the right label for that cell.
What is the best way to fix this?
Here is the code:
var variableToPass: String!
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell : MainCell! = tableView.dequeueReusableCellWithIdentifier("MainCell") as! MainCell
variableToPass = label1.text
cell.label1.userInteractionEnabled = true
let tapLabel = UITapGestureRecognizer(target: self, action: #selector(ViewController.tapLabel(_:)))
cell.label1.addGestureRecognizer(tapLabel)
return cell as MainCell
}
func tapCommentPost(sender:UITapGestureRecognizer) {
print(variableToPass)
}
I think you forget to set the tap.tag = indexPath.row for identify which cell you tabbed for Find, for example
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell : MainCell! = tableView.dequeueReusableCellWithIdentifier("MainCell") as! MainCell
variableToPass = label1.text
cell.label1.userInteractionEnabled = true
let tapLabel = UITapGestureRecognizer(target: self, action: #selector(ViewController.tapLabel(_:)))
cell.label1.tag = indexPath.row
tapLabel.numberOfTapsRequired = 1
cell.label1.addGestureRecognizer(tapLabel)
return cell as MainCell
}
func tapLabel(sender:UITapGestureRecognizer) {
let searchlbl:UILabel = (sender.view as! UILabel)
variableToPass = searchlbl.text!
print(variableToPass)
}
There are several issues with your current code: (1) You're setting variableToPass in cellForRowAtIndexPath:, so assuming label1.text is the label belonging to the cell, as the table loads, the variableToPass will always contain the label text of the last loaded cell. (2) cellForRowAtIndexPath: can be called multiple times for each cell (for example, as you scroll) so you could be adding multiple gesture recognizers to a single cell.
In order to resolve issue #1, remove the variableToPass variable entirely and instead directly access the gesture's label view. In order to resolve issue #2, I'd recommend adding the gesture recognizer to your custom MainCell table view cell, but if you don't want to do that, at least only add a gesture recognizer if one isn't already there.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MainCell") as! MainCell
if cell.label1.gestureRecognizers?.count == 0 {
cell.label1.userInteractionEnabled = true
let tapLabel = UITapGestureRecognizer(target: self, action: #selector(ViewController.tapCommentPost(_:))) // I assume "tapLabel" was a typo in your original post
cell.label1.addGestureRecognizer(tapLabel)
}
return cell
}
func tapCommentPost(sender:UITapGestureRecognizer) {
print((sender.view as! UILabel).text) // <-- Most important change!
}
I have a tableview with custom cell that contain 1 label and 1 button. The button is use for everytime I tap it, increase the number inside label, example if my label value is 0 then everytime I tap the button it is increase by 1
The problem is I have a lot of data, example I have 20 and everytime I set a value for the label when I scroll all the value is changed
this is my code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("testCell", forIndexPath: indexPath)
let pos = cell.viewWithTag(6) as! UIButton
pos.addTarget(self, action: #selector(testTableViewController.pos(_:)), forControlEvents: .TouchUpInside)
pos.tag = indexPath.row
return cell
}
func pos(sender: UIButton) {
let position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let indexPath = self.tableView.indexPathForRowAtPoint(position)
let cell: UITableViewCell = self.tableView.cellForRowAtIndexPath(indexPath!)! as UITableViewCell
let countNo = cell.viewWithTag(7) as! UILabel
var counter:Int = Int(countNo.text!)!
counter = counter + 1
countNo.text = String(counter)
}
please help me how to solve this problem. I have search a lot of web to find the answer, example like make dequeueReusableCellWithIdentifier nil but in Swift 2 dequeueReusableCellWithIdentifier never nil and a lot more with no one is work
I need some hint how to solve this problem
Here is your answer.
Initialise one array having number of objects same as your tableview's number of row. Initially insert value "0" or blank string (if do not want to display any number in label initially) for each object.
ex,
var arrValues:NSMutableArray = NSMutableArray()
for _ in 1...numberOfrow
{
arrValues.addObject("0")
}
Now in cellForRowAtIndexPath method , display text of label from this array
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("testCell", forIndexPath: indexPath)
let pos = cell.viewWithTag(6) as! UIButton
**let countNo = cell.viewWithTag(7) as! UILabel
countNo.text = String(arrValues.objectAtIndex(indexPath.row))**
pos.addTarget(self, action: #selector(testTableViewController.pos(_:)), forControlEvents: .TouchUpInside)
pos.tag = indexPath.row
return cell
}
On button click method replace object at particular index with incremented number. See your updated method as below.
func pos(sender: UIButton) {
let position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let indexPath = self.tableView.indexPathForRowAtPoint(position)
let cell: UITableViewCell = self.tableView.cellForRowAtIndexPath(indexPath!)! as UITableViewCell
let countNo = cell.viewWithTag(7) as! UILabel
var counter:Int = Int(countNo.text!)!
counter = counter + 1
countNo.text = String(counter)
**arrValues.replaceObjectAtIndex(indexPath.row, withObject: String(counter))**
}
So in cellForRowAtIndexPath , it will display updated number in label text
I have two ViewControllers, one is GoalsViewController and the other one is AddNewGoalViewController.
The GoalsViewController is useful to delete goals (cells) and to add new goals (cells). There is a UITableView and a button, Add new Goal. When the user presses the Add new Goal button, it will pass to AddNewGoalViewController. In AddNewGoalViewController users will select workout, notifications (how many times they want to be notified), and how much they want to run, walk or do any other work.
I checked a tutorial (click on word "tutorial" to check it), and it was helpful. The problem is that it is implementing empty cells. Download my project to check it better.
EDIT: After spending A LOT of time looking into your project, I found the issue.
Click on your Main.Storyboard file. Click on the file inspector. Uncheck Size Classes. Done. Your project works !
This seems to be an XCode bug. If you check again Size Classes, your project should still work.
The fix is therefore to uncheck and then check Size Classes in the File Inspector of your Main.storyboard file.
NONETHELESS: My syntax advice is still valid, it makes for cleaner code:
Well, did you check the solution of the exercise?
There is a link at the end of the page ;)
1st Difference:
var workouts = [Workout]()
var numbers = [Workout]()
func loadSampleMeals() {
let workouts1 = Workout(name: "Run", number: "1000")!
let workouts2 = Workout(name: "Walk", number: "2000")!
let workouts3 = Workout(name: "Push-Ups", number: "20")!
workouts += [workouts1, workouts2, workouts3]
numbers += [workouts1, workouts2, workouts3]
}
should be:
var workouts = [Workout]()
func loadSampleMeals() {
let workouts1 = Workout(name: "Run", number: "1000")!
let workouts2 = Workout(name: "Walk", number: "2000")!
let workouts3 = Workout(name: "Push-Ups", number: "20")!
workouts += [workouts1, workouts2, workouts3]
}
2nd Difference:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Table view cells are reused and should be dequeued using a cell identifier.
let cellIdentifier = "DhikrTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! GoalsTableViewCell
// Fetches the appropriate meal for the data source layout.
let dhikr = workouts[indexPath.row]
let number = numbers[indexPath.row]
cell.nameLabel.text = dhikr.name
cell.numberLabel.text = number.number
//cell.photoImageView.image = dhikr.photo
//cell.ratingControl.rating = dhikr.rating
return cell
}
should be:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Table view cells are reused and should be dequeued using a cell identifier.
let cellIdentifier = "DhikrTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! GoalsTableViewCell
// Fetches the appropriate meal for the data source layout.
let dhikr = workouts[indexPath.row]
cell.nameLabel.text = dhikr.name
cell.numberLabel.text = dhikr.number
//cell.photoImageView.image = dhikr.photo
//cell.ratingControl.rating = dhikr.rating
return cell
}
P.S.:
class Workout {
// MARK: Properties
var name: String
//var notifications: Int
var number: Int
// MARK: Initialization
init?(name: String, number: Int) {
// Initialize stored properties.
self.name = name
//self.notifications = notifications
self.number = number
// Initialization should fail if there is no name or if the rating is negative.
if name.isEmpty || number < 0{
return nil
}
}
}
number will never be < 0, perhaps you meant == 0?.
My self.totalPriceLabel show's total price of all shop Product.It works fine but when is i scroll the cell the go off screen due to dequeueReusableCellWithIdentifier self.totalPriceLabel gets incorrect value.i am saving value in array which is stored in NSUserDefaults.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : CartCell? = tableView.dequeueReusableCellWithIdentifier("cartCell") as! CartCell!
if(cell == nil)
{
cell = CartCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cartCell")
}
cell?.itemCount.layer.cornerRadius = 5
cell?.clipsToBounds = true
cell?.itemCount.layer.borderWidth = 1
cell?.itemCount.layer.borderColor = UIColor.blackColor().CGColor
cell?.itemMinus.tag = indexPath.row
cell?.itemPlus.tag = indexPath.row
cell?.itemDelete.tag = indexPath.row
let key = self.readArray[indexPath.row]
cell?.itemCount.text = String("\(key.allValues[0])")
let tupleVar = getProductNameFromCharacter(String("\(key.allKeys[0])"))
cell?.itemName.text = tupleVar.tempName
cell?.itemPrice.text = String("\(tupleVar.price)")
//Actual Logic
let tempCount = key.allValues[0] as! Double
let nextItemPrice = (cell!.itemPrice.text! as NSString).doubleValue * tempCount
self.totalPriceLabel.text = String("\((self.totalPriceLabel.text! as NSString).doubleValue + nextItemPrice)")
return cell!
}
Issue: As scroll cell getting wrong values.for self.totalPriceLabel.
self.totalPriceLabel.text = String("((self.totalPriceLabel.text! as
NSString).doubleValue + nextItemPrice)")
How to get cell value which just goes out off screen ? how to fix this issue due to scrolling?
cellForRowAtIndexpath is the wrong place to do that calculation. You are assuming that iOS will call this function once for each cell. This isn't the case. This function is called to display a single cell. It could very well get called multiple times for the same cell as you scroll up and down.
You should be updating that total when you add or remove items from the underlying data (self.readArray).
Also, add code to change the total when the quantity button is tapped.
If you want more specific help, post the entire controller.