I've got a simple to do list app, and I would like the items in the list to appear after the app is closed. What I have so far does not do it, not sure if everything is in the right place?
Code in my first ViewController:
var list = [String]()
class FirstViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var myTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
cell.textLabel?.text = list[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
list.remove(at: indexPath.row)
myTableView.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
myTableView.reloadData()
if let x = UserDefaults.standard.object(forKey: "cell") as? [String]! {
list = x
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Code in my second ViewController:
class SecondViewController: UIViewController {
#IBOutlet weak var input: UITextField!
#IBAction func addItemButton(_ sender: AnyObject) {
list.append(input.text!)
input.text = ""
UserDefaults.standard.set(input.text, forKey: "cell")
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
You are reloading the tableview at viewDidAppear before getting the data. Get your data from user defaults first (set list) and then reload the table view.
Hint:-
override func viewDidAppear(_ animated: Bool) {
if let x = UserDefaults.standard.object(forKey: "cell") as? [String]! {
list = x
myTableView.reloadData()
}
}
Related
I use below code for get selected items of tab bar controller. My UITabbar has 7 view controllers(there are 3 items in More tab).
this code work only for 5 tabs but it don`t return selected index of items on More!
import UIKit
class CustomTabbarController: UITabBarController{
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
print(self.selectedIndex)
}
}
Following code worked for me. I had to redesign moreTableView to follow my app design. Function 'didSelectRowAt' returns what index is selected.
This code is added to 'UITabBarController' class.
var moreTableView: UITableView?
weak var currentTableViewDelegate: UITableViewDelegate?
func customizeMoreTableView() {
moreTableView = moreNavigationController.topViewController?.view as? UITableView
currentTableViewDelegate = moreTableView?.delegate
moreTableView?.delegate = self
moreTableView?.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (viewControllers?.count ?? 4) - 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let moreCell = UITableViewCell()
let item = viewControllers?[indexPath.row + 4].tabBarItem
moreCell.textLabel?.text = item?.title
moreCell.textLabel?.textColor = .white
moreCell.imageView?.image = item?.image
moreCell.imageView?.tintColor = .white
moreCell.backgroundColor = .black
return moreCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
currentTableViewDelegate?.tableView!(tableView, didSelectRowAt: indexPath)
}
Get selected item like this :
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
print(tabBar.items?.index(of: item))
}
I'm trying to create two tableViews in one UIViewController. But when I'm trying to assign value to UILabel, getting an error: fatal error: unexpectedly found nil while unwrapping an Optional value
I wonder why, I have almost the same code for TableViewController with one tableView and it works with no issues. It looks like these UI Labels are not initialized when trying to assign value to it. But don't understand how to fix it.
It fails here:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: UITableViewCell?
if tableView == self.guestsTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "guestCell", for: indexPath) as! GuestAtTableTableViewCell
if let guestsTable = guestsTableFetchedResultsController?.object(at: indexPath) {
print(guestsTable.guestName) // works fine, prints the value
print(cell.guestNameLabel.text) //fails here with error fatal error: unexpectedly found nil while unwrapping an Optional value
cell.guestNameLabel.text = guestsTable.guestName
cell.openTimeLabel.text = String(describing: guestsTable.openTime)
cell.cellDelegate = self
}
}
else if tableView == self.ordersTableView {
cell = tableView.dequeueReusableCell(withIdentifier: "orderCell", for: indexPath)
//to be done
}
// Configure the cell...
return cell!
}
Full code of this class:
import UIKit
import CoreData
class TableUIViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, CellWithButtonDelegate {
//The following two variables will not be nil because prepare for segue will set them
var tableName: String?
var table: TablesTable? = nil
fileprivate var currentTableSession: TableSessionTable? {
get {
let tableSessionTable = TableSessionTable()
return tableSessionTable.getCurrentTableSession(table: table!)
}
}
fileprivate var guestsTableFetchedResultsController: NSFetchedResultsController<GuestsTable>?
fileprivate var ordersTableFetchedResultsController: NSFetchedResultsController<OrdersTable>?
#IBOutlet weak var tableNameLabel: UILabel!
#IBOutlet weak var tableCapacityLabel: UILabel!
#IBOutlet weak var tableCountOfGuestsLabel: UILabel!
#IBOutlet weak var tableDescriptionTextView: UITextView!
#IBAction func closeTableButtonPressed(_ sender: UIButton) {
}
#IBOutlet weak var guestsTableView: UITableView!
#IBOutlet weak var ordersTableView: UITableView!
#IBAction func addGuestButtonPressed(_ sender: UIButton) {
let guestsTable = GuestsTable()
let tablesTable = TablesTable()
let table = Table(tableName: tableName!, tableCapacity: 0, locationX: nil, locationY: nil, tableImage: nil)
try? guestsTable.addNewGuest(table: tablesTable.getOrCreateTable(table: table))
updateUI()
}
#IBAction func addOrderButtonPressed(_ sender: UIButton) {
}
override func viewDidLoad() {
guestsTableView.dataSource = self
guestsTableView.delegate = self
guestsTableView.register(GuestAtTableTableViewCell.self, forCellReuseIdentifier: "guestCell")
ordersTableView.dataSource = self
ordersTableView.delegate = self
ordersTableView.register(UITableViewCell.self, forCellReuseIdentifier: "orderCell")
updateUI()
}
func didPressButton(table: TablesTable) {
}
private func updateUI () {
let tableView = guestsTableView
let context = AppDelegate.viewContext
let request : NSFetchRequest<GuestsTable> = GuestsTable.fetchRequest()
request.predicate = NSPredicate(format: "table= %#", currentTableSession!)
request.sortDescriptors = [NSSortDescriptor(key: "guestName", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))]
guestsTableFetchedResultsController = NSFetchedResultsController<GuestsTable>(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
try? guestsTableFetchedResultsController?.performFetch()
tableView?.reloadData()
}
private func updateUI1 () {
let tableView = ordersTableView
let context = AppDelegate.viewContext
let request : NSFetchRequest<OrdersTable> = OrdersTable.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "menuItem", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))]
ordersTableFetchedResultsController = NSFetchedResultsController<OrdersTable>(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
try? ordersTableFetchedResultsController?.performFetch()
tableView?.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: UITableViewCell?
if tableView == self.guestsTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "guestCell", for: indexPath) as! GuestAtTableTableViewCell
if let guestsTable = guestsTableFetchedResultsController?.object(at: indexPath) {
print(guestsTable.guestName) // works fine, prints the value
print(cell.guestNameLabel.text) //fails here with error fatal error: unexpectedly found nil while unwrapping an Optional value
cell.guestNameLabel.text = guestsTable.guestName
cell.openTimeLabel.text = String(describing: guestsTable.openTime)
cell.cellDelegate = self
}
}
else if tableView == self.ordersTableView {
cell = tableView.dequeueReusableCell(withIdentifier: "orderCell", for: indexPath)
//to be done
}
// Configure the cell...
return cell!
}
func numberOfSections(in tableView: UITableView) -> Int {
if tableView == self.guestsTableView {
return guestsTableFetchedResultsController?.sections?.count ?? 1
}
else if tableView == self.ordersTableView {
return ordersTableFetchedResultsController?.sections?.count ?? 1
}
else {return 1}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.guestsTableView {
if let sections = guestsTableFetchedResultsController?.sections, sections.count > 0 {
return sections[section].numberOfObjects
}
else {
return 0
}
}
else if tableView == self.ordersTableView {
if let sections = ordersTableFetchedResultsController?.sections, sections.count > 0 {
return sections[section].numberOfObjects
}
else {
return 0
}
}
else {return 0}
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if tableView == self.guestsTableView {
if let sections = guestsTableFetchedResultsController?.sections, sections.count > 0 {
return sections[section].name
}
else {
return nil
}
}
else if tableView == self.ordersTableView {
if let sections = ordersTableFetchedResultsController?.sections, sections.count > 0 {
return sections[section].name
}
else {
return nil
}
}
else {return nil}
}
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
if tableView == guestsTableView {
return guestsTableFetchedResultsController?.sectionIndexTitles
}
else {
return ordersTableFetchedResultsController?.sectionIndexTitles
}
}
func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
if tableView == guestsTableView {
return guestsTableFetchedResultsController?.section(forSectionIndexTitle: title, at: index) ?? 0
}
else if tableView == ordersTableView {
return ordersTableFetchedResultsController?.section(forSectionIndexTitle: title, at: index) ?? 0
}
else {return 0}
}
}
And full code of UITableViewCell class:
import UIKit
class GuestAtTableTableViewCell: UITableViewCell {
weak var cellDelegate: CellWithButtonDelegate?
#IBOutlet weak var guestNameLabel: UILabel!
#IBOutlet weak var openTimeLabel: UILabel!
#IBAction func didPressButton(_ sender: UIButton) {
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
I guess you have a xib for your UITableViewCell register the xib instead of the class.
Use the following:
guestsTableView.register(UINib.init(nibName: "GuestAtTableTableViewCell", bundle: nil), forCellReuseIdentifier: "guestCell")
As you have created a prototype cell in the storyboard itself you should select the cell in the storyboard and set its identifier there. Next remove the register line from your code for guestCell. It should work
Repeated on two projects and searched in vain so I hope someone can help...
Created a basic TableViewController and one TableViewCell. Run and press the first button, scroll down and other random buttons also show the same change?
TableViewController
import UIKit
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 99
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ButtonCell", for: indexPath) as! ButtonCell
cell.rowLabel.text = "\(indexPath.row)"
cell.tapAction = { (cell) in
self.showAlertForRow(tableView.indexPath(for: cell)!.row)
}
return cell
}
// MARK: - Extracted method
func showAlertForRow(_ row: Int) {
let alert = UIAlertController(
title: "BEHOLD",
message: "Cell at row \(row) was tapped!",
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Gotcha!", style: UIAlertActionStyle.default, handler: { (test) -> Void in
self.dismiss(animated: true, completion: nil)
}))
self.present(
alert,
animated: true,
completion: nil)
}
}
Table View Cell
// ButtonCell.swift
import UIKit
class ButtonCell: UITableViewCell {
var tapAction: ((UITableViewCell) -> Void)?
#IBOutlet weak var rowLabel: UILabel!
#IBOutlet weak var button: UIButton!
#IBAction func buttonTap(_ sender: AnyObject) {
button.setTitle("Correct", for: .normal)
tapAction?(self)
}
}
Lets begin with the basics. You don't need this:
cell.tapAction = { (cell) in
self.showAlertForRow(tableView.indexPath(for: cell)!.row)
}
You better use the apple framework:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
showAlertForRow(indexPath.row)
}
Second create a method in you cell like
import UIKit
class ButtonCell: UITableViewCell {
var tapAction: ((UITableViewCell) -> Void)?
#IBOutlet weak var rowLabel: UILabel!
#IBOutlet weak var button: UIButton!
#IBAction func buttonTap(_ sender: AnyObject) {
button.setTitle("Correct", for: .normal)
tapAction?(self)
}
func createCell() {
button.setTitle("Your button title", for: normal)
}
}
and call the createCell method in your
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
cell.createCell()
...
}
Hope I could help but try to start with the basics here: https://developer.apple.com/reference/uikit/uitableviewdelegate
This is happening because you are dequeuing your UITableViewCells. In order to solve the problem you should use the prepareForReuse() method in your ButtonCell. You can save the states of all your buttons and when a cell is being dequeued you can just set the title of the button in this cell in the prepareForReuse() method.
I'm pretty new to swift but I've managed to follow along for the most part. However, there's an issue with my code that the code itself can't even identity apparently(I'm not receiving any error signs). I'm trying to click on a row from the table view to make it go to the following page but I don't think the code is recognizing the didselectrow method. Maybe one of you more experienced persons can help me out.
Here's the code:
import UIKit
import Foundation
class OnePercentersViewController: UIViewController, UITableViewDataSource
{
var copiedExecutiveArray : [String] = NSArray() as! [String]
var identities : [String] = NSArray() as! [String]
override func viewDidLoad()
{
super.viewDidLoad()
let copyExecutiveNames : ExecutiveArray = ExecutiveArray()
copiedExecutiveArray = copyExecutiveNames.executiveNames
identities = copyExecutiveNames.executiveNames
}
//how many sections in table
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
//returns int (how many rows)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return copiedExecutiveArray.count
}
//contents of each cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")//UITableViewCell()
let personName = copiedExecutiveArray[indexPath.row]
cell?.textLabel?.text = personName
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let execName = identities[indexPath.row]
let viewController = storyboard?.instantiateViewController(withIdentifier: execName)
self.navigationController?.pushViewController(viewController!, animated: true)
print("button clicked")
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
}
I haven't checked other parts of your code, but to make tableView(_:didSelectRowAt:) work, your ViewController needs to conform to UITableViewDelegate:
class OnePercentersViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
Also you need to connect the delegate of the UITableView to your ViewController in your storyboard. Or you can do it in code, if you have an #IBOutlet to the UITableView. Anyway, not only dataSource, but also delegate.
And this is not a critical issue, but you can write the first two lines of the class as:
var copiedExecutiveArray : [String] = []
var identities : [String] = []
After spending a day and a half watching Youtube videos and reading comments to similar problems, tt took trial and error but I finally got it thanks to you guys!It finally clicked when I read that I had to connect the delegate to the ViewController through the storyboard, so thanks for that!
Here's the final code for those with similar issue:
import UIKit
import Foundation
class OnePercentersViewController: UIViewController,UITableViewDataSource, UITableViewDelegate
{
var copiedExecutiveArray : [String] = []
var identities : [String] = []
override func viewDidLoad()
{
super.viewDidLoad()
let copyExecutiveNames : ExecutiveArray = ExecutiveArray()
copiedExecutiveArray = copyExecutiveNames.executiveNames
identities = copyExecutiveNames.executiveNames
}
//how many sections in table
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
//returns int (how many rows)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return copiedExecutiveArray.count
}
//contents of each cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let personName = copiedExecutiveArray[indexPath.row]
cell.textLabel?.text = personName
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let execName = identities[indexPath.row]
let viewController = storyboard?.instantiateViewController(withIdentifier: execName)
self.navigationController?.pushViewController(viewController!, animated: true)
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
}
i am working on TODO app,it was all completed and was running well but suddenly it begins to give an error "fatal error: unexpectedly found nil while unwrapping an Optional value".Need Some Guide!
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
#IBOutlet weak var tableView: UITableView!
var tasks : [Task] = [ ]
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(_ animated: Bool) {
getdata()
tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let task = tasks[indexPath.row]
if task.isimportant{
cell.textLabel?.text = " ★ \(task.name!)"
}else{
cell.textLabel?.text = task.name!
}
return cell
}
func getdata() {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do{
tasks = try context.fetch(Task.fetchRequest())
}
catch {
print ("Failed!")
}
}
}
You should always avoid unwrapping optionals with an ! because of the danger of encountering a runtime error if the optional is missing. Try the following:
let taskName = task.name ?? "No name"
if task.isimportant{
cell.textLabel?.text = " ★ \(taskName)"
}else{
cell.textLabel?.text = taskName
}