Trouble reusing TableViewCells in Swift - ios

I have some trouble reusing cells in swift. I want the code below to only execute for the cells where post.altC.isEmpty actually is true. The problem is that it makes botBtnsStackView.isHidden = true for all cells, even though altC is not empty in all. What am I doing wrong?
The code below is from my PostCell file(just a part of the configureCell code at the bottom, but it's this part that is going wrong):
if post.altC.isEmpty == true {
botBtnsStackView.isHidden = true
} else {
altCLabel.text = post.altC["text"] as? String
if let votes = post.altC["votes"]{
self.altCVotesLbl.text = "\(votes)"
}
}
cellForRowAt:
func tableView(_ tableView: UITableView, cellForRowAt indexpath: IndexPath) -> UITableViewCell {
let post = posts[indexpath.row]
if let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexpath) as? PostCell{
cell.configureCell(post: post)
return cell
} else {
return PostCell()
}
}
ConfigureCell from PostCell file:
func configureCell(post: Post) {
self.post = post
//ALT A
if post.altA.isEmpty == false {
altALabel.text = post.altA["text"] as? String
if let votes = post.altA["votes"]{
self.altAVotesLbl.text = "\(votes)"
}
} else {
print("No data found in Alt A")
}
//ALT B
if post.altB.isEmpty == false {
altBLabel.text = post.altB["text"] as? String
if let votes = post.altB["votes"]{
self.altBVotesLbl.text = "\(votes)"
}
} else {
print("No data found in Alt B")
}
//ALTD
if post.altD.isEmpty == false {
altDLabel.text = post.altD["text"] as? String
if let votes = post.altD["votes"]{
self.altDVotesLbl.text = "\(votes)"
}
} else {
altDView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0)
altDVotesView.isHidden = true
altDLabelView.isHidden = true
}
//ALT C
if post.altC.isEmpty == true {
print("No data found in Alt C")
//altCView.isHidden = true
botBtnsStackView.isHidden = true
} else {
altCLabel.text = post.altC["text"] as? String
if let votes = post.altC["votes"]{
self.altCVotesLbl.text = "\(votes)"
}
}

Cells are reused. So anything you do in an if statement you need to undo in the else.
So your snipped needs to be changed to:
if post.altC.isEmpty == true {
botBtnsStackView.isHidden = true
} else {
botBtnsStackView.isHidden = false
altCLabel.text = post.altC["text"] as? String
if let votes = post.altC["votes"]{
self.altCVotesLbl.text = "\(votes)"
}
}
Your others need to be update as well. For example, for "ALT A":
if post.altA.isEmpty == false {
altALabel.text = post.altA["text"] as? String
if let votes = post.altA["votes"]{
self.altAVotesLbl.text = "\(votes)"
}
} else {
altALabel.text = ""
self.altAVotesLbl.text = ""
print("No data found in Alt A")
}
I'm guessing a bit here but this gives you an idea. Adjust this to suit your actual needs. The important thing to remember is that whatever you set for one condition, you must reset for other conditions.
Unrelated but you should rewrite your cellForRowAt as:
func tableView(_ tableView: UITableView, cellForRowAt indexpath: IndexPath) -> UITableViewCell {
let post = posts[indexpath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexpath) as! PostCell
cell.configureCell(post: post)
return cell
}
This is a case where a force-cast is appropriate. You want your app to crash early on in development if you have setup your cell identifier and cell type incorrectly. Once setup properly and working, it can't crash at runtime unless you do something to break it.

Related

Dequeue Reusable Cell crashes when calling dequeued cell

I am attempting to have a table view that lists multiple things and allows a user to go through and select multiple cells with checkboxes. My code works up until a certain point, the problem is that the app crashes with the following error
Fatal error: Unexpectedly found nil while unwrapping an Optional value
whenever I call the following code
swift let currentCell = recommendToFriendTableView.cellForRow(at: selectedRow[i]) as? RecommendToFriendsTableViewCell
Here is the method where we set up the cells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (tableView == self.friendListTableView) {
let cell: FriendListTableViewCell = tableView.dequeueReusableCell(withIdentifier: "FriendListCell") as! FriendListTableViewCell
let rowNumber = (indexPath as NSIndexPath).row
var name = ""
if searchActive {
name = filtered[rowNumber]
}
else {
name = names[rowNumber]
}
cell.friendNameLabel.text = name
cell.friendNameLabel.backgroundColor = tableViewBgColor
cell.friendNameLabel.textColor = textColor
cell.recommendToFriendButton.layer.borderWidth = 1
cell.recommendToFriendButton.layer.borderColor = tableViewBgColor.cgColor
cell.recommendToFriendButton.layer.cornerRadius = 6
cell.recommendToFriendButton.backgroundColor = buttonBgColor
cell.backgroundColor = tableViewBgColor
//set target for buttons
cell.recommendToFriendButton.tag = rowNumber
cell.recommendToFriendButton.addTarget(self, action:#selector(recommendToFriendButtonClicked), for: UIControl.Event.touchUpInside)
return cell
}
else {
let cell: RecommendToFriendsTableViewCell = tableView.dequeueReusableCell(withIdentifier: "RecommendToFriendsCell") as! RecommendToFriendsTableViewCell
let rowNumber = (indexPath as NSIndexPath).row
// set the content view background color
cell.contentView.backgroundColor = tableViewBgColor
// set the text color
cell.nameLabel.textColor = textColor
var dict_friend = NSMutableDictionary()
if searchActive {
dict_friend = filteredFriendsArray[rowNumber]
}
else {
dict_friend = friendsArray[rowNumber]
}
let name = dict_friend["name"] as! String
cell.nameLabel.text = name
let friendUID = dict_friend["uid"] as! String
cell.friendID = friendUID
let imageAddress = dict_friend["photo"] as? String
if imageAddress != "unavailable" && imageAddress != nil && imageAddress != ""{
//Swift forces us to wrap strings as optional to use them in logic
if let imageURL = imageAddress as String? {
//Swift forces us to wrap strings as optional to use them in logic
if let image = imageURL as String? {
//We convert the string into a URL and get the image
let url = URL(string: image)
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
if error != nil {
print(error!)
return
}
//We create a new async thread to download and update the image
DispatchQueue.main.async {
//imageView.image = UIImage(data: data!)
cell.photoImageView.image = UIImage(data:data!)
}
}).resume()
}
} else {
cell.photoImageView!.image = UIImage(named: "placeholder-profile-male.png")
}
} else {
cell.photoImageView!.image = UIImage(named: "placeholder-profile-male.png")
}
cell.checkBoxImageView.image = cell.checkBoxImageView.image!.withRenderingMode(.alwaysTemplate)
cell.checkBoxImageView.tintColor = textColor
// Style the profile photo to show in a circle
cell.photoImageView.layer.borderWidth = 0
cell.photoImageView.layer.borderColor = tableViewBgColor.cgColor
// Set cornerRadius = a square UIImageView frame size width / 2
// In our case, UIImageView height = width = 60 points
cell.photoImageView.layer.cornerRadius = 30
cell.photoImageView.clipsToBounds = true
cell.selectionStyle = .none // to prevent cells from being "highlighted"
return cell
}
}
This is the method where we interact with them. The crash happens on a cellForRow call for a cell that is out of view (aka dequeued)
var firstFriendName: String = ""
var numberOfFriends = 0
if let selectedRow = recommendToFriendTableView.indexPathsForSelectedRows {
numberOfFriends = selectedRow.count
for i in 0..<selectedRow.count {
let currentCell = recommendToFriendTableView.cellForRow(at: selectedRow[i]) as! RecommendToFriendsTableViewCell
let friendID = currentCell.friendID
idList.append(",\(friendID)")
}
let firstSelectedCell = recommendToFriendTableView.cellForRow(at: selectedRow[0]) as! RecommendToFriendsTableViewCell
firstFriendName = firstSelectedCell.nameLabel.text!
After about a day of experimenting, I've yet to figure out the actual problem (other than the observation that it appears to be in regards to calling a dequeued cell)
Any help is appreciated.
When this line
let currentCell = recommendToFriendTableView.cellForRow(at: selectedRow[i]) as! RecommendToFriendsTableViewCell
crashes this means you access a non-visble cell so either use
if let currentCell = recommendToFriendTableView.cellForRow(at: selectedRow[i]) as? RecommendToFriendsTableViewCell { }
or better use the dataSource array of the table to get the data that you want to gran wrongly from the cell

Unable to add dynamic data in expandable tableview iOS swift?

I'm new to iOS development I'm trying to implement expandable table with dynamic data which comes from server. I'm using https://github.com/amratab/ThreeLevelAccordian this expandable table view.
In this library they added statically like below code.
cells.append(TLAHeaderItem(value: "Bathroom" as AnyObject, imageURL: "bathroom_grey_32.png"))
cells.append(TLACell(value: "Shower" as AnyObject))
cells.append(TLASubItem(value: "Shower pores should be cleaned effectively by brushing." as AnyObject))
cells.append(TLACell(value: "Tap" as AnyObject))
cells.append(TLASubItem(value: "Taps must be washed with soap and all the salt removed." as AnyObject))
cells.append(TLACell(value: "Toilet" as AnyObject, imageURL: "toilet_grey_32.png"))
cells.append(TLASubItem(value: "Should be made stains and germs free." as AnyObject))
cells.append(TLAHeaderItem(value: "Bedroom" as AnyObject, imageURL: "bedroom_grey_32.png"))
cells.append(TLACell(value: "Bed" as AnyObject))
cells.append(TLASubItem(value: "Remove all the dust." as AnyObject))
cells.append(TLACell(value: "Dressing" as AnyObject))
cells.append(TLAHeaderItem(value: "Kitchen" as AnyObject, imageURL: "kitchen_grey_32.png"))
cells.append(TLACell(value: "Utensils" as AnyObject))
cells.append(TLASubItem(value: "There are many type of utensils like tongs, rolling pin, pan, non stick pans. Wash them all." as AnyObject))
cells.append(TLACell(value: "Sink" as AnyObject))
cells.append(TLASubItem(value: "Clean the sink" as AnyObject))
in cellforrowindexpath they are using like this.
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = self.cells[(indexPath as NSIndexPath).row]
let value = item.value as? String
if let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) {
cell.textLabel?.text = value
let label = cell.textLabel!
cell.imageView?.image = nil
if let headerImage = item.imageURL, let image = UIImage(named: headerImage) {
cell.imageView?.image = image
}
if let accessoryView = accessory(for: indexPath, and: .expand) {
cell.accessoryView = accessoryView
} else {
cell.accessoryType = UITableViewCellAccessoryType.none
cell.accessoryView = nil
}
if let _ = item as? TLAHeaderItem {
if let headerFont = headerCellFont {
cell.textLabel?.font = headerFont
}
if let headerCellBackgroundColor = self.headerCellBackgrondColor {
cell.backgroundColor = headerCellBackgroundColor
}
if let headerCellTextColor = self.headerCellTextColor {
cell.textLabel?.textColor = headerCellTextColor
}
} else if (item as? TLASubItem != nil) {
if isMultiline {
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.numberOfLines = 0
label.sizeToFit()
}
cell.accessoryView = nil
cell.accessoryType = UITableViewCellAccessoryType.none
if let subItemCellBackgrondColor = self.subItemCellBackgrondColor {
cell.backgroundColor = subItemCellBackgrondColor
}
if let subItemCellTextColor = self.subItemCellTextColor {
cell.textLabel?.textColor = subItemCellTextColor
}
if let subItemCellFont = self.subItemCellFont {
cell.textLabel?.font = subItemCellFont
}
} else {
if let itemCellBackgrondColor = self.itemCellBackgrondColor {
cell.backgroundColor = itemCellBackgrondColor
}
if let itemCellTextColor = self.itemCellTextColor {
cell.textLabel?.textColor = itemCellTextColor
}
if let itemCellFont = self.itemCellFont {
cell.textLabel?.font = itemCellFont
}
}
return cell
}
return UITableViewCell()
}
instead of adding statically i want to add dynamically array of data. to the cell.
Example:
cell.textLabel?.text = self.tableViewData[indexPath.row]

Hide imageView and Label by setting some kind of flag

Can you guys give me some help to hide the image and name if the message it's from the same user... I want only to show it for the first message...and if that user send more not to show anymore until another Id appear... like whatsapp does it..
currently I m having like this to show u an example
[![enter image description here][1]][1]
var isTheSameUser = false
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let selectedChat = chat[indexPath.row]
let myId = String(describing:UserDefaults.standard.value(forKey: "user_id")!)
let messageUserId = String(describing:selectedChat.owner_id)
if messageUserId == myId {
return myMessageCell(indexPath: indexPath)
}else {
return userMessageCell(indexPath: indexPath)
}
}
func myMessageCell(indexPath :IndexPath) -> UITableViewCell {
let cell = self.mainTableView.dequeueReusableCell(withIdentifier: "MyMessageTableViewCell", for: indexPath) as! MyMessageTableViewCell
let selectedChat = self.chat[indexPath.row]
let myId = String(describing:UserDefaults.standard.value(forKey: "user_id")!)
// Show only for the first message
// photo image
if !isTheSameUser {
cell.profileImageView.isHidden = false
cell.profileNameLabel.isHidden = false
} else {
cell.profileImageView.isHidden = true
cell.profileNameLabel.isHidden = true
}
if let userInfo = getUserMemberOf(userId: messageUserId) {
cell.profileImageView.imageFromURL(urlString: userInfo["photo"] as! String)
} else {
cell.profileImageView.image = #imageLiteral(resourceName: "accountIcon")
}
cell.profileNameLabel.text = "\(String(describing: cell.userProfileInfo!["name"]!))"
return cell
You need check the previous chat messsage id like for every message
if indexPath.row != 0 {
let prevItem = chat[indexPath.row - 1]
let currentItem = chat[indexPath.row]
if prevItem.owner_id! == currentItem.owner_id! {
// hide label and image
}else {
// show them
}
}
else {
// show them
}

Swift: Table View is only returning one cell

I'm attempting to load a table view with two different prototype cells. profileCell should only load once and at the top of the table view. dogCell should count an array of dog objects named dogs downloaded from firebase. Currently, only the first cell is displaying correctly.
I think the numberOfRowsInSection method isn't accurately counting the dog objects in the dogs array. When I put a breakpoint on return dogs.count + 1 and po dogs.count the debugger keeps outputting 0.
When I use return dogs.count the table view loads but with only the profile cell. If I use return dogs.count + 1(to account for the profile cell at the top) an exception is thrown when constructing dogCell: "fatal error: Index out of range"
Perhaps I need to change the way my tableview is reloading data?
Here's my code:
class DogTableViewController: UITableViewController {
var user = User()
let profileCell = ProfileTableViewCell()
var dogs = [Dog]()
override func viewDidLoad() {
super.viewDidLoad()
let userDogRef = Database.database().reference().child("users").child(user.uid!).child("dogs")
let userProfileImageView = UIImageView()
userProfileImageView.translatesAutoresizingMaskIntoConstraints = false
userProfileImageView.widthAnchor.constraint(equalToConstant: 40).isActive = true
userProfileImageView.heightAnchor.constraint(equalToConstant: 40).isActive = true
userProfileImageView.layer.cornerRadius = 20
userProfileImageView.clipsToBounds = true
userProfileImageView.contentMode = .scaleAspectFill
userProfileImageView.image = UIImage(named: "AppIcon")
navigationItem.titleView = userProfileImageView
//MARK: Download dogs from firebase
userDogRef.observe(.childAdded, with: { (snapshot) in
if snapshot.value == nil {
print("no new dog found")
} else {
print("new dog found")
let snapshotValue = snapshot.value as! Dictionary<String, String>
let dogID = snapshotValue["dogID"]!
let dogRef = Database.database().reference().child("dogs").child(dogID)
dogRef.observeSingleEvent(of: .value, with: { (snap) in
print("Found dog data!")
let value = snap.value as? NSDictionary
let newDog = Dog()
newDog.name = value?["name"] as? String ?? ""
newDog.breed = value?["breed"] as? String ?? ""
newDog.creator = value?["creator"] as? String ?? ""
newDog.score = Int(value?["score"] as? String ?? "")
newDog.imageURL = value?["imageURL"] as? String ?? ""
newDog.dogID = snapshot.key
URLSession.shared.dataTask(with: URL(string: newDog.imageURL!)!, completionHandler: { (data, response, error) in
if error != nil {
print(error!)
return
}
newDog.picture = UIImage(data: data!)!
self.dogs.append(newDog)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}).resume()
})
}
})
tableView.estimatedRowHeight = 454
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dogs.count + 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let profileCell = tableView.dequeueReusableCell(withIdentifier: "profileCell", for: indexPath) as! ProfileTableViewCell
profileCell.nameLabel.text = user.name
profileCell.totalReputationLabel.text = String(describing: user.reputation!)
profileCell.usernameLabel.text = user.username
return profileCell
} else {
let dogCell = tableView.dequeueReusableCell(withIdentifier: "dogCell", for: indexPath) as! DogTableViewCell
dogCell.dogBreedLabel.text = dogs[indexPath.row].breed
dogCell.dogNameLabel.text = dogs[indexPath.row].name
dogCell.dogScoreLabel.text = String(describing: dogs[indexPath.row].score)
dogCell.dogImageView.image = dogs[indexPath.row].picture
dogCell.dogCreatorButton.titleLabel?.text = dogs[indexPath.row].creator
dogCell.dogVotesLabel.text = "0"
return dogCell
}
}
}
I actually found a solution shortly after writing this question, but I think it might be helpful for others to read.
Because the first indexPath.row is dedicated to a profile cell, I should not have been using the indexPath.row to navigate my dogs array. Instead I should have been using indexPath.row - 1 to get the correct dogs index.
Here's the section I updated:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let profileCell = tableView.dequeueReusableCell(withIdentifier: "profileCell", for: indexPath) as! ProfileTableViewCell
profileCell.nameLabel.text = user.name
profileCell.totalReputationLabel.text = String(describing: user.reputation!)
profileCell.usernameLabel.text = user.username
return profileCell
} else {
let dogCell = tableView.dequeueReusableCell(withIdentifier: "dogCell", for: indexPath) as! DogTableViewCell
dogCell.dogBreedLabel.text = dogs[indexPath.row - 1].breed
dogCell.dogNameLabel.text = dogs[indexPath.row - 1].name
dogCell.dogScoreLabel.text = String(describing: dogs[indexPath.row - 1].score)
dogCell.dogImageView.image = dogs[indexPath.row - 1].picture
dogCell.dogCreatorButton.titleLabel?.text = dogs[indexPath.row - 1].creator
dogCell.dogVotesLabel.text = "0"
return dogCell
}
}

Automatically saving changes in a cell to object when editing finishes?

im having a real nightmare with my project where i need to save cell contents to an object, for each object in an array. I cant get this to work by looping through table cells adn array objects and trying to match them all up.
So my next idea was to add didFinishEditing related functions into the cellForRowAt function?
Im not sure this would work either, but this is what i have:
Each row here has a label for the set, a picker for the reps that can be scrolled to a number, and a textfield to put a weight. Then i save each row as an object storing the set, rep and weight.
Issue is when editing this, how can i save these again overwriting the old values? Hence my plan above to use didFinishEditing methods.
My previous plan was the code below, but i cant figure out the annotated part. So i was hoping someone had guidance on how i can approach saying when editing rather than this save button function that doesnt work!
func saveUserExerciseSets() {
if userExercise == nil {
print("CREATING A FRESH SET OF SETS FOR THE NEW EXERCISE")
for cell in self.customSetsTable.visibleCells as! Array<NewExerciseTableViewCell> {
print("SAVING THESE CELLS \(customSetsTable.visibleCells)")
let newUserExerciseSet = UserExerciseSet(context: self.managedObjectContext)
newUserExerciseSet.setPosition = Int64(cell.setNumber.text!)!
newUserExerciseSet.setReps = Int64(cell.repsPicker.selectedRow(inComponent: 0))
newUserExerciseSet.parentExerciseName = self.userExerciseName.text
if self.localeIdentifier == "en_GB" {
let kgWeight = Measurement(value: Double(cell.userExerciseWeight.text!)!, unit: UnitMass.kilograms)
newUserExerciseSet.setWeight = kgWeight as NSObject?
newUserExerciseSet.initialMetricSystem = self.localeIdentifier
} else if self.localeIdentifier == "en_US" {
let lbsWeight = Measurement(value: Double(cell.userExerciseWeight.text!)!, unit: UnitMass.pounds)
newUserExerciseSet.setWeight = lbsWeight as NSObject?
newUserExerciseSet.initialMetricSystem = self.localeIdentifier
}
let fetchRequest: NSFetchRequest<UserExercise> = UserExercise.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "name == %#", self.exerciseNameToAddTo!)
do {
let parentExercise = try self.managedObjectContext.fetch(fetchRequest).first
parentExercise?.addToExercisesets(newUserExerciseSet)
print("SET ADDED TO EXERCISE")
} catch {
print("Fetching Routine Failed")
}
}
} else if self.userExercise != nil {
print("UPDATING EXISTING SETS FOR THE EXISTING EXERCISE")
let cells = self.customSetsTable.visibleCells as! Array<NewExerciseTableViewCell>
for cell in cells {
let exerciseSets = self.userExercise?.exercisesets?.allObjects as! [UserExerciseSet]
let sortedexerciseSets = exerciseSets.sorted { ($0.setPosition < $1.setPosition) }
let cellsSet = sortedexerciseSets //match the sortedexerciseSets set object to the cell index positions
cellsSet.setPosition = Int64(setsCell.setNumber.text!)!
cellsSet.setReps = Int64(setsCell.repsPicker.selectedRow(inComponent: 0))
if self.localeIdentifier == "en_GB" {
let kgWeight = Measurement(value: Double(cell.userExerciseWeight.text!)!, unit: UnitMass.kilograms)
cellsSet.setWeight = kgWeight as NSObject?
} else if self.localeIdentifier == "en_US" {
let lbsWeight = Measurement(value: Double(cell.userExerciseWeight.text!)!, unit: UnitMass.pounds)
cellsSet.setWeight = lbsWeight as NSObject?
}
cellsSet.parentExerciseName = self.userExerciseName.text
}
}
do {
try self.managedObjectContext.save()
print("THE SET HAS BEEN SAVED")
} catch {
fatalError("Failure to save context: \(error)")
}
delegate?.didFinishEditing()
self.dismiss(animated: true, completion: nil)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? NewExerciseTableViewCell
else {
fatalError("Unexpected Index Path")
}
cell.backgroundColor = UIColor.customBackgroundGraphite()
cell.textLabel?.textColor = UIColor.white
cell.repsPicker.dataSource = self
cell.repsPicker.delegate = self
configure(cell, at: indexPath)
return cell
}
func configure(_ cell: NewExerciseTableViewCell, at indexPath: IndexPath) {
// configuring cells when theres a loaded exercise causes the issues --------------------
if self.userExercise != nil {
print("RESTORING CELLS FOR THE EXISTING EXERCISE")
let unsortedExerciseSets = self.userExercise?.exercisesets?.allObjects as! [UserExerciseSet]
let exerciseSets = unsortedExerciseSets.sorted { ($0.setPosition < $1.setPosition) }
let cellsSet = exerciseSets[indexPath.row]
cell.setNumber.text = String((indexPath.row) + 1)
let indexRow = Int(cellsSet.setReps)
print("INDEX ROW INT IS \(indexRow)")
cell.repsPicker.selectRow(indexRow, inComponent: 0, animated: true) //fix this crashing issue!
let localeIdentifier = Locale(identifier: UserDefaults.standard.object(forKey: "locale") as! String)
let setWeight = cellsSet.setWeight as! Measurement<UnitMass>
let formatter = MassFormatter()
formatter.numberFormatter.locale = localeIdentifier
formatter.numberFormatter.maximumFractionDigits = 2
if localeIdentifier.usesMetricSystem {
let kgWeight = setWeight.converted(to: .kilograms)
let finalKgWeight = formatter.string(fromValue: kgWeight.value, unit: .kilogram)
let NumericKgResult = finalKgWeight.trimmingCharacters(in: CharacterSet(charactersIn: "0123456789.").inverted)
cell.userExerciseWeight.text = NumericKgResult
} else {
let lbsWeight = setWeight.converted(to: .pounds)
let finalLbWeight = formatter.string(fromValue: lbsWeight.value, unit: .pound)
let NumericLbResult = finalLbWeight.trimmingCharacters(in: CharacterSet(charactersIn: "0123456789.").inverted)
cell.userExerciseWeight.text = NumericLbResult
}
} else if self.userExercise == nil {
print("NEW SET CELL ADDED FOR FRESH EXERCISE")
cell.setNumber.text = String((indexPath.row) + 1)
}
}
Try something like this to match the setIds correctly. That's where I think the issue is.
for x in sortedexerciseSets {
if x.setPosition == Int64(setsCell.setNumber.text!)! {
//save
}
}
Proper way to do it would be to have an array of those sets (I guess, since you tagged core-data, they are instances of NSManagedObject?). When user does ANY change in the cell (write new value in the text field or scroll to another value for reps) you need to update the approproate object in your array immediately. Then you could call save on NSManagedObjectContext when you're sure you want to save changes, or just call rollback on the context to cancel all changes.

Resources