How to display UiDatePicker to labels in tableview cell - ios

My project is a reminder list and has only two view controllers(vc).
The first displays the tableview using Subtile style on the tableview cell. The second vc has two text labels, the date picker and save button.
My questions;
1) How do I send the time only to the label I have created in the tableview cell?
2) When adding the date picker to xcdatamodeld (core data), under Attribute what is the Type? I have tried Double, but that didn't work.
Greatly appreciate your support.
import UIKit
class AddEventViewController: UIViewController {
#IBOutlet weak var addReminderTextField: UITextField!
#IBOutlet weak var addInformationTextField: UITextField!
var datePicker: UIDatePicker!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.isTranslucent = false
}
override func viewDidLoad() {
super.viewDidLoad()
datePicker = UIDatePicker()
datePicker.center = view.center
view.addSubview(datePicker)
}
#IBAction func cancelButtonTapped(_ sender: Any) {
navigationController!.popViewController(animated: true)
}
#IBAction func saveButtonTapped(_ sender: Any) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let task = Task(context: context)
task.title = addReminderTextField.text!
task.subtitle = addInformationTextField.text!
(UIApplication.shared.delegate as! AppDelegate).saveContext()
navigationController!.popViewController(animated: true)
}
}
And here is my tableview code...
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath)
let task = tasks[indexPath.row]
cell.textLabel?.text = task.title!
cell.detailTextLabel?.text = task.subtitle
return cell
}
func getTasks() {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do {
tasks = try context.fetch(Task.fetchRequest())
}
catch {
print("Fetching Failed")
}
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
if editingStyle == .delete {
let task = tasks[indexPath.row]
context.delete(task)
(UIApplication.shared.delegate as! AppDelegate).saveContext()
do {
tasks = try context.fetch(Task.fetchRequest())
}
catch {
print("Fetching Failed")
}
}
tableView.reloadData()
}
}

Related

How to fix deleted task being restored in Userdefaultrs

I'm making a TodoList app.
If you swipe a task from the list to delete it and then add a new task, the deleted task will be restored.
Use storyboard and UIKit.
I want to keep it deleted, what should I do? ..
mac 10.15.7
xcode 12.1
import UIKit
class ViewController: UIViewController {
#IBOutlet var tableView: UITableView!
var tasks = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "リスト"
tableView.delegate = self
tableView.dataSource = self
if !UserDefaults().bool(forKey: "setup") {
UserDefaults().set(true, forKey: "setup")
UserDefaults().set(0, forKey: "count")
}
updateTasks()
}
func updateTasks() {
tasks.removeAll()
guard let count = UserDefaults().value(forKey: "count") as? Int else {
return
}
for x in 0..<count {
if let task = UserDefaults().value(forKey: "task_\(x+1)") as? String {
tasks.append(task)
}
}
tableView.reloadData()
}
#IBAction func didTapAdd() {
let vc = storyboard?.instantiateViewController(identifier: "entry") as! EntryViewController
vc.title = "リストに追加"
vc.update = {
//非同期処理 更新を優先
DispatchQueue.main.async {
self.updateTasks()
}
}
navigationController?.pushViewController(vc, animated: true)
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let vc = storyboard?.instantiateViewController(identifier: "task") as! TaskViewController
vc.title = "リストに追加"
vc.task = tasks[indexPath.row]
navigationController?.pushViewController(vc, animated: true)
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = tasks[indexPath.row]
return cell
}
//タスクを削除
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
let index = indexPath.row
tasks.remove(at: index)
let userDefaults = UserDefaults.standard
userDefaults.set(tasks, forKey: "tasks")
userDefaults.removeObject(forKey: "tasks")
tableView.reloadData()
}
}
Is remove (at :) different?
import UIKit
class EntryViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var field: UITextField!
var update: (() -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
field.delegate = self
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "保存", style: .done, target: self, action: #selector(saveTask))
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
saveTask()
return true
}
#objc func saveTask() {
guard let text = field.text, !text.isEmpty else {
return
}
guard let count = UserDefaults().value(forKey: "count") as? Int else {
return
}
let newCount = count + 1
UserDefaults().set(newCount, forKey: "count")
UserDefaults().set(text, forKey: "task_\(newCount)")
update?()
navigationController?.popViewController(animated: true)
}
}
How to save UserDefaults?
The problem I see is; in updateTasks function, you get the tasks from UserDefaults by keys as task_1, task_2 etc. But when deleting a specific task, lets say task_2, you are just removing it from tasks array, not deleting it from UserDefaults. So whenever you call updateTasks function, the deleted task re-appears.
In your EntryViewController, change the saveTask function with following:
#objc func saveTask() {
guard let text = field.text, !text.isEmpty else {
return
}
let tasks = UserDefaults.standard.array(forKey: "tasks") as? [String] ?? []
tasks.append(text)
UserDefaults.standard.set(tasks, forKey: "tasks")
update?()
navigationController?.popViewController(animated: true)
}
In your ViewController, change the following functions:
func updateTasks() {
tasks.removeAll()
tasks = UserDefaults.standard.array(forKey: "tasks") as? [String] ?? []
tableView.reloadData()
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
tasks.remove(at: indexPath.row)
let userDefaults = UserDefaults.standard
userDefaults.set(tasks, forKey: "tasks")
updateTasks()
}

UITableViewCell public function not executing

var list = [String]()
#IBOutlet weak var TableView: UITableView!
override func viewDidLoad() {
self.title = "Routines"
TableView.delegate = self
TableView.dataSource = self
super.viewDidLoad()
}
//refresh view when going back to this viewcontroller
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("Test Worked")
TableView.reloadData()
}
//generating rows
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return (list.count)
}
//returning text in UITableViewCell
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = UITableViewCell(style:
UITableViewCell.CellStyle.default, reuseIdentifier:
"prototype1")
print("printed")
cell.textLabel?.text = list[indexPath.row]
return cell
}
//deleting rows
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
{
if editingStyle == UITableViewCell.EditingStyle.delete{
deleteAllData("ToDo")
self.list.remove(at: indexPath.row)
TableView.reloadData()
}
}
#IBAction func didAdd() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(identifier: "addRoutinePage")as! addRoutinePage
self.navigationController?.pushViewController(vc, animated: true)
}
//function to get data from core data
func getData()
{
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "ToDo")
request.returnsObjectsAsFaults = false
do{
//fetching data from coredata
let result = try context.fetch(request)
for data in result as! [NSManagedObject]
{
//appending the list from the value in coredata (attribute) or entity
self.list.append(data.value(forKey: "title")as! String)
print("append success")
}
}catch {
print("failed")
}
}
What is wrong with my code? Everything seems to work except for the UITableViewCell, the print command I entered just to check if the function is executed didn't even work. I tried TableView.reloadData() but it still didn't work. Logically if the problem is with the public function or data source or delegate it won't even generate any rows, but rows are generated. I tried resizing the cell height size too but it still won't work. Please help!
There are a few errors with the code:
You need to reload once the data fetching from CoreData is complete.
func getData() {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "ToDo")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
for data in result as! [NSManagedObject] {
self.list.append(data.value(forKey: "title")as! String)
}
self.TableView.reloadData()
} catch {
print(error)
}
}
Also, don't forget to call the getData function.
override func viewDidLoad() {
super.viewDidLoad()
title = "Routines"
TableView.delegate = self
TableView.dataSource = self
getData()
}

Saving the right row in a TableView

I`m a Beginner in swift and i have tried to build a shopping list app with a tableView in it. Nearly everthing works, except:
When you reorder the rows, quit the app, and going back, the new row order was not saved.
Any ideas?
This is the important part:
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let movedObject = shoppingList[sourceIndexPath.row]
shoppingList.remove(at: sourceIndexPath.row)
shoppingList.insert(movedObject, at: destinationIndexPath.row)
}
But in will not work.....
Here is the whole code:
import UIKit
import CoreData
var shoppingList: [NSManagedObject] = [ ]
class ShoppingList_1: UIViewController, UITableViewDelegate,UITableViewDataSource {
//Anzahl Spalten -->
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
//**************************
//Zeilen: dynamisch; abhängig von Anzahl items in Liste -->
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return shoppingList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = shoppingList[indexPath.row]
let cell = Cell.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
// <-- Prototype Cell für Ausschnitt/Sicht des Bildschirms
cell.textLabel?.text = item.value(forKeyPath: "itemName") as? String
cell.detailTextLabel?.text = "\(indexPath.row)"
return cell
}
//free to use
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
print("Daten geladen!\n")
let movedObject = shoppingList[sourceIndexPath.row]
shoppingList.remove(at: sourceIndexPath.row)
shoppingList.insert(movedObject, at: destinationIndexPath.row)
NSLog("%#", "\(sourceIndexPath.row) => \(destinationIndexPath.row) \(shoppingList)")
// To check for correctness enable: self.tableView.reloadData()
}
//*****************************************************************************************************
//Durch wischen entfernen -->
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete
{
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {return}
let managedContext = appDelegate.persistentContainer.viewContext
managedContext.delete(shoppingList[indexPath.row])
do {
try managedContext.save()
shoppingList.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
} catch let err as NSError {
print("12345", err)
}
}
}
#IBOutlet weak var AddButton: UIButton!
#IBOutlet weak var AddItem: UITextField!
#IBOutlet weak var Cell: UITableView!
#IBAction func EditTopRightButton(_ sender: UIBarButtonItem) {
self.Cell.isEditing = !self.Cell.isEditing
sender.title = (self.Cell.isEditing) ? "Done" : "Edit"
}
//Button Action
#IBAction func AddButton2_Test(_ sender: Any) {
print("My test")
let a:Float = 2
let b:Float = 3
let Ergebnis:Float = a+b
print(Ergebnis)
if (AddItem.text != "")
{
self.save(AddItem.text!)
}
Cell.reloadData()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {return}
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Item")
do {
shoppingList = try managedContext.fetch(fetchRequest)
} catch let err as NSError {
print("Failed to fetch items", err)
}
}
func save(_ itemName: String){
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Item", in: managedContext)!
let item = NSManagedObject(entity: entity, insertInto: managedContext)
item.setValue(itemName, forKey: "itemName")
do {
try managedContext.save()
shoppingList.append(item)
} catch let err as NSError {
print("Failed to save item",err)
}
}
//*****************************************************************************************************
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
Cell.delegate = self
Cell.dataSource = self
AddItem.delegate = self
}
//HINZU-->
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
//*****************************************************************************************************
// extensions -->
extension ShoppingList_1 : UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
AddItem.resignFirstResponder()
return true
}
}
//***************************************
Current Working
In your code, Table view is loaded with data from Coredata at viewWillAppear. Data inserted to core data is not updated when you change the order in TableView.
So even you changed order of cell and corder in Array. Every time viewWillAppear calls Data is again fetched from Coredata with no order.
ViewWillAppear will call every time view display in screen. Incase you are coming back to this view from any other presented view ViewWillAppear will call.
Sollution
You can create a new attribute in table describing order of item in Coredata Entity & Sort the item with this order after fetching.
Refer this answer to know how to set display order with core data
https://stackoverflow.com/a/31907857/4845644
Or If your requirement is just to persist order to ViewController instances existence you need to change core data fetch code from viewWillAppear to viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
Cell.delegate = self
Cell.dataSource = self
AddItem.delegate = self
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {return}
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Item")
do {
shoppingList = try managedContext.fetch(fetchRequest)
} catch let err as NSError {
print("Failed to fetch items", err)
}
}

pass data from a table view Controller to View Controller using data stored in core data

I'm a little newbie and I have a doubt, I have a TableViewController and another ViewController that I have as a detailViewController, what I try to do is that when a cell is selected in the tableview, it presents the corresponding data stored in core data for that cell in the detailViewcontroller.
This is the file that controls the tableViewcontroller :
import UIKit
class CostumerTableViewController: UITableViewController {
var costumerArray:[Costumer] = []
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.reloadData()
self.fetchData()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return costumerArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let name = costumerArray[indexPath.row]
cell.textLabel?.text = name.costumerName!
return cell
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
if editingStyle == .delete {
let costumerDelete = costumerArray[indexPath.row]
context.delete(costumerDelete)
(UIApplication.shared.delegate as! AppDelegate).saveContext()
do {
costumerArray = try context.fetch(Costumer.fetchRequest())
} catch {
print(error)
}
}
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let Storyboard = UIStoryboard(name: "Main", bundle: nil)
let DvC = Storyboard.instantiateViewController(withIdentifier: "costumerDetailViewController") as! costumerDetailViewController
let n = costumerArray[indexPath.row]
let Cn = n.costumerName!
DvC.getCostumerName = Cn
self.navigationController?.pushViewController(DvC, animated: true)
}
func fetchData() {
// se crea el context
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do { // se hace el request del array
costumerArray = try context.fetch(Costumer.fetchRequest())
} catch {
print(error)
}
}
}
In the compilation does not give me any problem, some everything goes well the problem is that it does not present anything in the detail viewController label that in this case I try to send the data from this code.
This is the detailViewController code :
import UIKit
class costumerDetailViewController: UIViewController {
var getCostumerName = String()
#IBOutlet weak var labelName: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
labelName.text! = getCostumerName
}
}
First Check Cn has value or "" on this line.
let Cn = n.costumerName
Change your code in class costumerDetailViewController for declare getCostumerName
var getCostumerName = "" //for avoid crash. if value goes nil.
Use Print() in viewDidLoad and debug it.
Hope this will help you.

How to retrieve data corresponding to a particular UITableViewCell from core data?

I'm doing a project in swift 3.0 and I have two UIViewControllers and one of them has three text fields. In that UIViewController once the data is entered in the textfields and when the save button is pressed the data will be saved to core data. In my core data module, the name of my entity is "Task" and it has got four attributes namely: amount, age, name and isImportant(all are strings except the last one). The code is shown below
import UIKit
class AddTaskViewController: UIViewController {
var isRowTapped :Bool?
#IBOutlet weak var textFiels: UITextField!
#IBOutlet weak var firstTextField: UITextField!
#IBOutlet weak var secondTextField: UITextField!
#IBOutlet weak var isImp: UISwitch!
override func viewDidLoad() {
}
#IBAction func buttonTabbed(_ sender: AnyObject) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let task = Task(context: context)
task.name = textFiels.text
task.age = firstTextField.text
task.amount = secondTextField.text
task.isImportant = isImp.isOn
(UIApplication.shared.delegate as! AppDelegate).saveContext()
print("Data saved successfully")
navigationController!.popViewController(animated: true)
}
}
Even though three values will be saved to core data, only the attribute called "name" will be taken out from core data and will be printed on cells in the second view controller where i have my table view (it is more like an identity name). What I want to know is since I'm entering three values initially to core data in the initial view controller, once a particular row is selected in the second view controller how do I get all the three values to correspond to that name attribute and re-assign them to my text fields in the initial view controller so that I could edit them and save again. The code of my second view controller is as below (tableviewViewController).
import UIKit
class DispalyViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableview: UITableView!
var tasks : [Task] = []
var isRowSelected :Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
loadData()
self.tableview.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadData(){
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do {
tasks = try context.fetch(Task.fetchRequest())
print("fetch sucess")
}catch{
print("fetch failed")
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("count is : \(tasks.count)")
return tasks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell ()
print("table view loaded")
let task = tasks[indexPath.row]
if task.isImportant{
cell.textLabel?.text = "😌 \(task.name!)"
}else{
cell.textLabel?.text = task.name
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "ShowNxtVC", sender: nil)
//isRowSelected = true
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let selectedRow = segue.destination as! AddTaskViewController
//selectedRow.isRowTapped = isRowSelected
}
//For swipe access allow
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
if editingStyle == .delete {
let task = tasks [indexPath.row]
context.delete(task)
(UIApplication.shared.delegate as! AppDelegate).saveContext()
do {
tasks = try context.fetch(Task.fetchRequest())
}catch{
print("fetchinh failed")
}
}
tableview.reloadData()
}
}

Resources