How do I use UIStepper to change a property in a Realm Model Object? - swift

I currently have a ViewController with a TableView inside it called SelectedListItemsViewController. This ViewController's TableView is populated by a custom cell class called SelectedListItemsTableViewCell.
I have an array of Realm Model Objects called selectedListItems, each of which has several properties. The SelectedListItemsTableViewCell populates the TableView with the listItem property of that indexPath.row's object, and each row has a UIStepper with a UILabel next to it that (as of now) shows UIStepper.value for each row. Ideally, the label will reflect the listItemWeight property of each row, and change it when incrementing or decrementing that row.
This is my custom cell:
class SelectedListItemsTableViewCell: UITableViewCell {
#IBOutlet var selectedListItemLabel: UILabel!
#IBOutlet weak var listItemWeightLabel: UILabel!
#IBOutlet weak var stepperControl: UIStepper!
#IBAction func stepperValueChanged(sender: UIStepper) {
listItemWeightLabel.text = Int(sender.value).description
}
}
And in my ViewController's cellForRowAtIndexPath, I've configured the cell like so:
// Configure the cell...
cell.selectedListItemLabel.text = selectedListItems[indexPath.row].listItem
cell.listItemWeightLabel.text = "\(selectedListItems[indexPath.row].listItemWeight)"
Which perfectly loads the listItem property, and the listItemWeight property shows up correctly, but as soon as I increment or decrement on the UIStepper it gets messed up.
How do I properly link my UILabel and UIStepper to the [indexPath.row].listItemWeight?

In the same method that gets called when your stepper updates, update your listItem. However, since this item is stored in your Realm database, you will have to get an instance of your Realm database and write the change to the database.
You can do this by having your TableViewCell hold on to an instance of the listItem. Your new TableViewCell class will look something like this:
class SelectedListItemsTableViewCell: UITableViewCell {
#IBOutlet var selectedListItemLabel: UILabel!
#IBOutlet weak var listItemWeightLabel: UILabel!
#IBOutlet weak var stepperControl: UIStepper!
var listItem: Item?
#IBAction func stepperValueChanged(sender: UIStepper) {
listItemWeightLabel.text = Int(sender.value).description
if let listItem = listItem {
let realm = try! Realm
try! realm.write {
listItem.listItemWeight = Int(sender.value) ?? 0
}
}
}
}

The above answer was helpful in leading me to the actual solution of my issue, but if anyone in the future is curious - I ended up using a closure.
In my custom cell class, I did
#IBAction func stepperValueChanged(sender: UIStepper) {
selectedListItemLabel.text = Int(sender.value).description
tapped?(self)
}
And in my view controller, I did
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! SelectedListItemsTableViewCell
cell.stepperControl.value = selectedListItems[indexPath.row].listItemWeight
// Configure the cell...
cell.tapped = { (selectedCell) -> Void in
selectedListItems[indexPath.row].listItemWeight = cell.stepperControl.value
}
Which allowed me to access each cell's UIStepper in the view controller file.
It helped to read flashadvanced's Option 2 answer in this thread.

Related

Custom UITableViewCell changes width randomly (swift)

I'm making a chess app for swift with a chat function. I upload my messages to firebase firestore and then, download them into a [Message] array and display them in a UITableView.
I've been looking around for this on stackoverflow and found that several people are having trouble with sizes of a custom UITableViewCell. I've run into the same problem, but in my case the width of the cell seems to randomly change every time I call .reloadData(). To illustrate :
The first 2 times or so when I type something in my chat it should look like this (the cells in the circle)
But as you can see after a few times this happens :
My code :
Custom cell class
class MessageCustomCell: UITableViewCell {
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var bgView: UIView!
#IBOutlet weak var leftImage: UIImageView!
#IBOutlet weak var messageBubble: UIView!
#IBOutlet weak var messageLabel: UILabel!
#IBOutlet weak var rightImage: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
messageLabel.numberOfLines = 0
messageBubble.layer.cornerRadius = 5
}
}
TableView delegate methods (TableView = messageView)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allMessages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = messageView.dequeueReusableCell(withIdentifier: "MessageCustomCell") as! MessageCustomCell
//cell.width = tableView.frame.width
let msg = allMessages[indexPath.row]
//cell.frame.size.width = messageView.frame.width
//cell.contentView.frame.size.width = messageView.frame.width
let date = msg.time
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "d/M/yy, h:mm"
let realDate = dateFormatter.string(from: date)
print(msg.fromUserName!)
if msg.fromUserName! == currentUserName {
cell.messageBubble.backgroundColor = UIColor(named: "lightSquare")
cell.messageLabel.textColor = .black
cell.rightImage.isHidden = true
} else {
cell.messageBubble.backgroundColor = UIColor(named: "darkSquare")
cell.messageLabel.textColor = .white
cell.leftImage.isHidden = true
}
cell.dateLabel.text = realDate
cell.messageLabel.text = msg.text!
return cell
}
In my MessageCustomcell.xib file I have a few constraints :
I've put the leftImage, messageBubble (UIView), rightImage in a horizontal stackview. The images have only width and height constraints. The label in the messageBubble has constraints to its superview (top,bottom,trailing,leading)
The stackView has constraints to the bgView (UIView), also top bottom trailing and leading.
Same for the bgView to the safe area.
I've tried setting the frame for the custom cell, but that didn't seem to work, so I've commented that out.
Really hope someone can help me out. If you guys need more info then please do let me know :)
Thanks all.
EDIT :
Here are my constraints for the custom cell xib file.
Alright thanks to #SPatel, who pointed out to make 2 separate .xib files for the receiver chat bubble and the sender chat bubble. This actually worked for my situation and was the right way to go in the first place, instead of manipulating one custom cell for both sender and receiver.
I'm thinking the constraint issue had to do with me trying to hide either the right image or the left image, to change the custom cell appearance for both sides. That must have messed up the whole constraints situation for the custom cell.
Anyway, happy man. Moving on!

Populating UI with info from tableview cell? - Swift

Hi I have tried to follow tutorials online but can't seem to get it working.
I am trying to populate a view controller with information from the pressed cell from a table view ... it picks up which cell has been selected but then opens the view controller twice... it also doesn't populate the ui label?
Please advise thank you.
Table View Class where user selects a cell ;
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell
title = currentCell.textLabel?.text
performSegue(withIdentifier: "passInfoSegue", sender: self)
}
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
if (segue.identifier == "passInfoSegue") {
// initialize new view controller and cast it as your view controller
let viewController = segue.destination as! NextViewController
// your new view controller should have property that will store passed value
viewController.passedValue = title!
}
}
Next View Controller ;
class NextViewController : UIViewController{
var passedValue : String!
#IBOutlet weak var featLabel: UITextView!
#IBOutlet weak var descripLabel: UITextView!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var ampImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
featLabel.text = passedValue
}
}

Delegate used to control a button inside a cell not working

I have a custom UIView with 3 tableviews, the tableviews are self-sizing depending on the content they have, and they a show a different nib when they are empty than when they have content. All of this is embedded in a scroll view and it's working already, my view scrolls and the tableviews display the content appropriately and they autosize properly, the scroll view's size is adjusting without problems either.
In two of the tableviews when the tableviews have items there are some buttons in the cell nib that I want to access along with the index of the cell clicked inside the View controller where I have defined the Table view.
Here in the pic I'm showing the tableViews each with one item, the Canastas tableView has just a delete item button and the Productos tableView has a delete item button and a stepper to increase or decrease the amount.
I found a solution involving delegates in StackOverflow
Get button click inside UI table view cell, which I implemented. But for some reason it isn't working and the code in the delegate method isn't being executed.
Here is my code:
CanastasViewCell
import UIKit
protocol CanastasViewCellDelegate: class {
func closeButtonTapped(at index: IndexPath)
}
class CanastasViewCell: UITableViewCell {
#IBOutlet weak var imagenProducto: UIImageView!
#IBOutlet weak var nombreProducto: UILabel!
#IBOutlet weak var descProducto: UILabel!
#IBOutlet weak var precioProducto: UILabel!
#IBOutlet weak var closeButton: UIButton!
weak var delegate: CanastasViewCellDelegate?
var indexPath: IndexPath!
override func awakeFromNib() {
super.awakeFromNib()
}
#IBAction func eliminarProducto(_ sender: AnyObject) {
self.delegate?.closeButtonTapped(at: indexPath)
}
}
CarritoViewController
import UIKit
class CarritoViewController: UIViewController, UITableViewDelegate,
UITableViewDataSource, CanastasViewCellDelegate {
func closeButtonTapped(at index: IndexPath) {
print("Button tapped at index:\(index)")
}
It looks like you're not setting the delegate inside CarritoViewController. You'll want to make sure that you set cell.delegate = self inside func tableView(UITableView, cellForRowAt: IndexPath).

Populate tableview using contacts framework

I want to populate a tableview with contact details that I have entered in the app.
first i have a table view controller that will show the list of entered contacts. its swift file looks like this.
import Contacts
import ContactsUI
class thecontacts: UITableViewController, CNContactPickerDelegate, UIPickerViewDelegate {
let contacts = CNMutableContact()
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell!
return cell
}
I want to populate this from another view controller. I want to populate this tableview with a persons name, and have it as a contact in the tableview. This view controllers swift file is:
import Contacts
class newContact: UIViewController {
//outlets
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var emailTextField: UITextField!
var tableViewController: newContact? = nil
override func viewDidLoad() {
}
#IBAction func addBuddy(sender: AnyObject) {
let contacts = CNMutableContact()
contacts.nickname = nameTextField!.text!;
contacts.emailAddresses = [CNLabeledValue(label: nil, value: emailTextField.text!)]
self.tableViewController?.addBuddy(contacts)
dismiss()
}
func dismiss(){
dismissViewControllerAnimated(true, completion: nil)
}
}
my tableViewController file is called thecontacts.swift. My new contact details viewController is called newContacts.swift.
the problem I have is that the details I enter into the newContact file are not appearing in my thecontacts table view.

Custom cell: fatal error: unexpectedly found nil while unwrapping an Optional value

I have a table view with custom cell that was created as .xib . I didnt use storyboard. I have a problem that I couldnt fill my table with the data which came from webservice result. Also, I have 4 labels in the custom cell. In my custom cell class, when I try to set labels for each items, It gives me fatal error like above.
Here is my code:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
...
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
{
let cell: ItemManagementTVCell = tableView?.dequeueReusableCellWithIdentifier("cell") as ItemManagementTVCell
if let ip = indexPath
{
let item: Item = self.itemList[indexPath.row] as Item
cell.setCell(item.itemName, status: item.itemStatus, duration: item.itemDuration, price: item.itemPrice)
}
return cell
}
}
And my custom cell class is here :
import UIKit
class ItemManagementTVCell: UITableViewCell {
#IBOutlet var lblItemName: UILabel!
#IBOutlet var lblItemPrice: UILabel!
#IBOutlet var lblItemDuration: UILabel!
#IBOutlet var lblItemStatus: UILabel!
override func awakeFromNib()
{
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
}
func setCell(name: String, status: Int, duration: Int, price: Int)
{
self.lblItemName.text = name
self.lblItemStatus.text = String(status)
self.lblItemDuration.text = "Duration: \(String(duration)) months"
self.lblItemPrice.text = String(price) + " $"
}
}
I am getting the error inside of "setCell" method block.
I have read a lot of questions and solutions and I tried all of them it doesnt work for me.
Thank you for your answers,
Best regards.
SOLUTION: I've solved this problem by linking the cell items to cell's own instead of linking to File's Owner. My problem has gone by doing this.
Another solution to the problem without having to link cell items to the cell owner:
let nib = UINib(nibName: "YOUR_CUSTOM_CELL_NIB_NAME", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "YOUR_CUSTOM_CELL_ID")
Your "cell" must be nil.
Using
tableView.dequeueReusableCellWithIdentifier("cell") as ItemManagementTVCell
Can return nil. You should use:
tableView.dequeueReusableCellWithIdentifier("cell" forIndexPath:indexPath) as ItemManagementTVCell
This way it guarantees cells is not nil.
EDIT: Maybe you can prevent the crash by putting if statements inside "setCell"
if var itemName = self.lblItemName {
itemName.text = name
}
Do that for every label you set inside it and check if the crash still happens. If it don't you must check why those labels are nil.