how to load UIStepper value from Coredata? - uitableview

I use CoreData in my project and I have uitableview and in every cell I have UIStepper. Now I can save UIStepper value in CoreData, For example when I click on + it's work fine and save the new value in the CoreDate and when I restart my App I can see my last uistepper value but when I click + it will star count from 1 , not from the last value I have and it will save the new value in the CoreData.
how I can load the last value from the core data and make my UIStepper start counting from this value (last value in core data)
my function
func stepper2 (sender: UIStepper){
let appD = UIApplication.shared.delegate as! AppDelegate
let context = appD.persistentContainer.viewContext
//save the object
let aa = Tasks[sender.tag]
aa.stepper = (sender.value)
do {
try context.save()
print("updated!")
print (aa)
print("stepper \(sender.tag) clicked. Its value \(sender.value)")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
///////////////////
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
let task = Tasks[indexPath.row]
cell.stepper2.tag = indexPath.row
cell.stepper2.addTarget(self, action: #selector(stepper2(sender: )), for: .valueChanged)
cell.ggg.text = task.mytext
cell.stepperV.text = String(task.stepper)
return cell
}

I don't see where you set the UISteppers value. You need something like this in your tableView(_:cellForRowAt:) implementation:
cell.stepperV.text = String(task.stepper)
cell.stepper2.value = task.stepper

Related

How to work with the Cosmo Raiting Library in table cells? (SWIFT)

I don't understand how to link the selection of a set of rating stars to each cell and save this value?
Cosmo lib: https://github.com/evgenyneu/Cosmos
My Code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCellTableViewCell
let currentNameItem = gameNameArray[indexPath.row]
cell.gameNameLabel?.text = currentNameItem["Name"] as? String
// MARK: - переменная из словаря - если true ставим галочку - если нет убираем
if (currentNameItem["isCompleted"] as? Bool) == true {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
let currentSubNameItem = gameSubNameArray[indexPath.row]
cell.subGameNameLabel?.text = currentSubNameItem["Name"] as? String
let currentScoreItem = gameScoreArray[indexPath.row]
cell.gameScoreValue?.text = currentScoreItem["Name"] as? String
let currentImageItem = gameImageArray[indexPath.row]
guard let url = URL(string: currentImageItem["Name"] as! String) else { return cell }
cell.gameImage.sd_setImage(with: url, completed: nil)
//I can set the rating value
cell.fiveStarRaiting.rating = 5
let currentRaitingItem = raitingArray[indexPath.row] //array where I would like to save the ratings
cell.fiveStarRaiting.rating = currentRaitingItem //here, the values from the rating array should be pulled up by the ide
//allows you to save the rating value at the end of the finger movement gesture
cell.fiveStarRaiting.didFinishTouchingCosmos = { [self] raiting in raitingArray.append(raitingStarValue)}
print(raitingArray.count)
//cell.testButton0.addTarget(self, action: #selector(testFuncButton(sender:)), for: .touchUpInside)
return cell
}
As you know, table view cells are reusable, so when you scrolls and when cells are disappeared then its values are also cleared that's how table view and collection view works.
So if you want to save those ratings then you can go with a local temporary dictionary.
e.g.
var ratingsArray = [Int:Float]()
store your indexpath as key in "ratingsArray" dictionary and set its value as cosmos ratings.
and set cosmos ratings values as prefill in "cellForRowAt" table view method,
if ratingsArray.keys.contains(indexPath.row) {
cell.fiveStarRaiting.rating = 5
}
else {
cell.fiveStarRaiting.rating = 0 // set starts default value here
}
cell.fiveStarRaiting.didFinishTouchingCosmos = { [self] rating in
ratingsArray[indexPath.row] = rating
}

dequeueReusableCell returns empty cell after table initialization

I have a table view that is initialized with three rows when loaded. Later, I want to extract cell data (from labels) and use it when that specific cell is selected by the user.
Even though initialization works well and I can see all the data being displayed, the dequeueReusableCell in the didSelectRowAt methods returns empty cells, with no data.
What is the problem?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? ArticleTableViewCell else {
fatalError("Whoopse, dequeueing the cell failed")
}
let title = cell.articleLabel.text
// Do other stuff
}
The title variable above will be empty, even though it's data is shown on the display.
Replace
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? ArticleTableViewCell else {
fatalError("Whoopse, dequeueing the cell failed")
}
with ( not recommended )
guard let cell = tableView.cellForRow(at:indexPath) as? ArticleTableViewCell else {
fatalError("Whoopse, dequeueing the cell failed")
}
but ##better## is to access the data source array with the clicked index
let item = arr[indexPath.row]

Swift Firebase Like Post in Table View

I am implementing a Question&Answer program in Swift, using Firebase. I want to have a like button in my tableViewCell. However, I am having problem because the post's data is in the tableView class and I can make changes on the like button in tableViewCell class. I need a data transfer between these two. Can anyone help me with this?
If it is going to help you to understand my problem, code in my table view:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let answerCell = tableView.dequeueReusableCell(withIdentifier: "AnswerCell") as! AnswerCell
let answer = answers[indexPath.row]
answerCell.answerText.text = answer.answerText
answerCell.username.text = "~ \(answer.username)"
answerCell.numberOfLikes.text = "\(answer.numberOflikes) liked this answer."
answerCell.answerText.numberOfLines = 0
return answerCell
}
I want to have a code like this in my table view cell. However, I cannot access the answer object's data.
#IBAction func likeButtonClicked(_ sender: UIButton) {
ref = Database.database().reference()
ref.child("answerLikes").child((answer.id).observeSingleEvent(of: .value, with: {
(snapshot) in
if let _ = snapshot.value as? NSNull {
sender.setImage(UIImage(named: "filledHeart.png"), for: .normal)
} else {
answerLikes = [Auth.auth().currentUser?.uid : true]
ref.child("answerLikes").child(answer.id).updateChildValues(answerLikes)
sender.setImage(UIImage(named: "emptyHeart.png"), for: .normal)
}
})
}
UPDATED
This is solution where you asked "I cannot access the answer object's data"
You can create a method in answerCell which receive an answer object.
func recieveAnswerObject(answer : Answer){
// here you will get answer object
// here i am assuming Answer is your model class
}
// now time to call it from your main UIViewController class to send answer object
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let answerCell = tableView.dequeueReusableCell(withIdentifier: "AnswerCell") as! AnswerCell
let answer = answers[indexPath.row]
// from here we send answer object
answerCell.recieveAnswerObject(answer)
answerCell.answerText.text = answer.answerText
answerCell.username.text = "~ \(answer.username)"
answerCell.numberOfLikes.text = "\(answer.numberOflikes) liked this answer."
answerCell.answerText.numberOfLines = 0
return answerCell
}
Now for the part where you asked how to data transfer between these two class
First way to achieve this
1.Make a delegate in AnswerCell class and confirm it to your Controller where you have written your tableView code.
2.When button is clicked fire a delegate and you will get callback in your mainViewController.
Second way to achieve this
1.Make an IBOulet for likeButtonClicked in AnswerCell class.
2.Dont't make IBAction.
3.Your code will look something like this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let answerCell = tableView.dequeueReusableCell(withIdentifier: "AnswerCell") as! AnswerCell
// action added to button
answerCell.likeButtonClicked.addTarget(self, action: #selector(likeButtonClicked), for: .touchUpInside)
// updated set tag to button
answerCell.likeButtonClicked.tag = indexPath.row
let answer = answers[indexPath.row]
answerCell.answerText.text = answer.answerText
answerCell.username.text = "~ \(answer.username)"
answerCell.numberOfLikes.text = "\(answer.numberOflikes) liked this answer."
answerCell.answerText.numberOfLines = 0
return answerCell
}
and write your below code in your tableview class
#IBAction func likeButtonClicked(_ sender: UIButton) {
//updated now tag is row position of button in cell and is equal to (indexPath.row) of that particular button.tag is equal to
let tag = sender.tag
// here indexPath.row can be replace by tag so
//let answer = answers[indexPath.row] == let answer = answers[tag]
// updated till here
ref = Database.database().reference()
ref.child("answerLikes").child((answer.id).observeSingleEvent(of: .value, with: {
(snapshot) in
if let _ = snapshot.value as? NSNull {
sender.setImage(UIImage(named: "filledHeart.png"), for: .normal)
} else {
answerLikes = [Auth.auth().currentUser?.uid : true]
ref.child("answerLikes").child(answer.id).updateChildValues(answerLikes)
sender.setImage(UIImage(named: "emptyHeart.png"), for: .normal)
}
})
}

How to get table all current row information

I am new to swift . i am doing my project programatically and I load data from api to the tableView and tableView like ios setting page ..
now i need all rows information when click "Add to cart" button. How can i do it?
here is my code sample :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: cartHeaderCell, for: indexPath) as! CartHeaderCell
cell.configureCell(indexPath.item)
return cell
case 1:
let obj = data?[indexPath.row]
var cell = UITableViewCell()
switch obj {
case is Addon:
cell = tableView.dequeueReusableCell(withIdentifier: addonCell, for: indexPath) as! AddonCell
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
cell.accessoryView = switchView
guard let addon = obj as? Addon else {
return cell
}
cell.textLabel?.text = "\(addon.name) + €\(addon.price)"
case is AddonGroup:
cell = tableView.dequeueReusableCell(withIdentifier: addonGroupCell, for: indexPath) as! AddonGroupCell
cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
guard let addonGroup = obj as? AddonGroup else {
return cell
}
if let addons = addonGroup.addonList {
cell.detailTextLabel?.text = ""
var selectedAddons = ""
for _addon in addons
{
if _addon.isSelect == true {
selectedAddons = selectedAddons + "\(_addon.name)"
}
}
cell.detailTextLabel?.text = selectedAddons
}
cell.textLabel?.text = addonGroup.name
...........................................
As Fahim was mentioning, you need to set up a data model that records that status of each cell before / during / after the user interaction with each cell. So when the cell goes off screen and then comes back on, it will be presented with the correct state of the model.
Secondly, for the UISwitchViews, you should be instantiating and adding those to the contentView within each cell in order to keep the cellForRow function clean and problem free. The reason leads me into my next point: how to record the status of each UISwitchView after the user has interacted with a UISwitchView. You are going to want to create a protocol and add a delegate within the UICollectionViewCell(that inherits class and the delegate should be a weak var), in order to update the model whenever the UISwitch is tapped.
If you have any more questions i can do my best to help!

core data app crash when adding more than 5 related objects

I have two core data entities, each with a to-many relationship to the other. I'm using a tableView to allow users to select which wageClasses are related to a given Proposal. The project is Swift 3, iOS 10.2.1, and I'm using the NSManagedObject subClasses from the Editor menu.
This all works great, until I try to add a sixth wageClass to a Proposal. Note: If I try to add any value other than the first 5 into the WageClass array, it crashes. But when I print the array it prints as many values as there are in the array. The app crashes with the error: unexpectedly found nil while unwrapping an Optional value.
I also get a Thread 1: EXC_BREAKPOINT error, but the Breakpoints navigator and lldb list no breakpoints.
I've tested this by trying to add the wageClasses individually, by adding them in different orders, and by creating up to ten wageClasses (to see if it was an issue with the last created wageClass not loading in the tableView) but no luck, I get the same result.
Here's where I'm adding:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "AddWageClassCell", for: indexPath)
let wageClass = wageClasses[indexPath.row]
let wageClassStatus = wageClass.value(forKey: "checked") as? Bool ?? true
cell.textLabel?.text = wageClass.value(forKey: "wageClassName") as? String
var accessoryType = UITableViewCellAccessoryType.none
var tintColor = UIColor.clear
if (wageClassStatus) {
accessoryType = UITableViewCellAccessoryType.checkmark
tintColor = UIColor.green
}
cell.accessoryType=accessoryType
cell.tintColor = tintColor
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let wageClassObject = self.wageClasses[indexPath.row]
var wageClassStatus = wageClassObject.value(forKey: "checked") as? Bool ?? false
wageClassObject.setValue(!wageClassStatus, forKey:"checked")
proposalToEdit?.addToWageClasses(wageClassObject)
do {
try
ad.saveContext()
} catch let error as NSError {
print("Cannot save object: \(error), \(error.localizedDescription)")
}
tableView.deselectRow(at: indexPath,animated:false)
tableView.reloadRows(at: [indexPath], with: .none)
}
Thanks for your comments!
I finally realized that I was force unwrapping a variable when I formatted a cell with wageClasses on a separate tableView on a separate xib. When I wrapped that in an if let statement
if let cell = tableView.cellForRow(at: indexPath) as? WageCell {
configureCell(cell: cell, indexPath: indexPath as NSIndexPath)
} else {
print("something is nil")
}
}
the crash went away.

Resources