1

I am having a problem while adding sections to my dynamic view. I want 4 different sections but I only want to add to one of the sections via my textfield.

I have tried this method over here: How to deal with dynamic Sections and Rows in iOS UITableView

Which I believe is on the right track however when I add something it doesn't show up which means I must be returning something wrong right? I just can't wrap my head around this!

The code below does not have any code in it from stackoverflow question above!

//  Recipe App
//  Created by Stefan Fletcher on 06/08/2019.
//  Copyright © 2019 Stefan Fletcher. All rights reserved.

import UIKit
import RealmSwift
import ChameleonFramework

class TodoListViewController: SwipeTableViewController, UITextFieldDelegate {

    @IBOutlet weak var textField: UITextField!

    @IBOutlet weak var searchBar: UISearchBar!

    let realm = try! Realm()

    var todoItems: Results<Item>?

    var selectedCategory: Category? {
        // Specify what should happen when a variable gets set with a new value
        didSet{
            loadItems()
        }
    }


    let copyFoodIconList: NSArray = NSArray()

    override func viewDidLoad() {

        super.viewDidLoad()

        textField.returnKeyType = UIReturnKeyType.done

        self.textField.delegate = self
        self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
        self.navigationController?.navigationBar.shadowImage = UIImage()
        self.navigationController?.navigationBar.titleTextAttributes =
            [NSAttributedString.Key.foregroundColor: UIColor.darkGray,
             NSAttributedString.Key.font: UIFont(name: "Avenir Next", size: 20)!]
    }


    let copiedFoodIconList : FoodIconList = FoodIconList()

    override func viewWillAppear(_ animated: Bool) {
        title = selectedCategory!.name
        self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
        self.navigationController?.navigationBar.shadowImage = UIImage()
        self.navigationController?.navigationBar.titleTextAttributes =
            [NSAttributedString.Key.foregroundColor: UIColor.darkGray,
             NSAttributedString.Key.font: UIFont(name: "Avenir Next", size: 20)!]

        let backButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
        self.navigationItem.backBarButtonItem = backButton
        self.view.backgroundColor = JDColor.appSubviewBackground.color

    }


    // MARK: - Tableview Datasource Methods
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return todoItems?.count ?? 1
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // Use super class Prototype Cell on storyboard


        let cell = super.tableView(tableView, cellForRowAt: indexPath)
        if let item = todoItems?[indexPath.row] {
            cell.textLabel?.text = item.title
            self.tableView.rowHeight = 58.0
            cell.accessoryType = item.done ? .checkmark : .none

            cell.textLabel?.textColor = UIColor.darkGray
            cell.textLabel?.font = UIFont(name:"Avenir Next", size:18)



        } else {
            cell.textLabel?.text = "No Items Added"
        }
        return cell
    }

    // MARK: - TableView Delegate Methods
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if let item = todoItems?[indexPath.row] {
            do {
                try realm.write {
                    // DELETE using Realm method called delete()
                    // realm.delete(item)
                    item.done = !item.done

                }
            } catch {
                print("Error update done status, \(error)")
            }
        }
        tableView.reloadData()
        tableView.deselectRow(at: indexPath, animated: true)
    }

    // TODO: 4
    // MARK: - Model Manipulation Methods
    func loadItems() {
        //READ using Realm
        todoItems = selectedCategory?.items.sorted(byKeyPath: "title", ascending: true)
        tableView.reloadData()
    }

    // MARK: - Delete Data From Swipe. Call method from super class
    override func updateModel(at indexPath: IndexPath) {
        if let deletedItem = todoItems?[indexPath.row] {
            do {
                try realm.write {
                    realm.delete(deletedItem)
                }
            } catch {
                print("Error deleting item, \(error)")
            }
        }
    }

    func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
        if (text == "\n") {
            textView.resignFirstResponder()
        }
        return true
    }


    func textFieldShouldReturn(_ textField: UITextField) -> Bool {

        //textField code

        textField.resignFirstResponder()  //if desired
        performAction()
        return true
    }

    func performAction() {

      if let currentCategory = self.selectedCategory {
            do {
                // CREATE and UPDATE using Realm method called realm.write()
                try self.realm.write {
                    let newItem = Item()
                    newItem.title = textField.text!
                    newItem.dateCreated = Date()
                    currentCategory.items.append(newItem)
                }
            }

            catch
            {
                print("Error saving new items, \(error) ")
            }

            //If text field is empty - Show error message

        }

        self.tableView.reloadData()
    }
    }




// MARK: - Implement Search Bar Methods
// Using extension to seperate out functionality

extension TodoListViewController: UISearchBarDelegate {

    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        todoItems = todoItems?.filter("title CONTAINS[cd] %@", searchBar.text!).sorted(byKeyPath: "dateCreated", ascending: true)

        tableView.reloadData()
    }

    // Finish write on search bar, change condition to the first view
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        if searchBar.text?.count == 0 {
            loadItems()
            // Being run in the background
            DispatchQueue.main.async {
                searchBar.resignFirstResponder()
            }
        }
    }
}

The expected results should be that there should be 4 sections created and one of the sections should be filling up with the textfield. Like my code does already just not in the whole table but in one of the sections

Fabian
  • 5,040
  • 2
  • 23
  • 35
  • Hey, you have `override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int` so you are telling tableView how many rows you want but you did not add `numberOfSections` function to tell how many sections – Lu_ Aug 22 '19 at 15:34
  • @Lu_ ah apologies I completely forgot to put my question that I have tried that already however when at runtime I try to add from text field but it goes into both sections when I only want it to go into one – Stefan Fletcher Aug 22 '19 at 15:37
  • that is because you are using `if let item = todoItems?[indexPath.row] ` this way you have only one array, is it array of sections or rows? – Lu_ Aug 22 '19 at 15:39
  • @Lu_ it is array of rows, sorry for all the questions my knowledge of swift is rubbish! So essentially there should be an array of rows inside one of the sections, so let’s say I have 5 sections but one the sections has that array that I can then add to or takeaway at runtime. Sorry! – Stefan Fletcher Aug 22 '19 at 15:44
  • see my answer, feel free to ask if something is not clear – Lu_ Aug 22 '19 at 15:50

1 Answers1

0

In your code you are missing

func numberOfSections(in tableView: UITableView) -> Int {
    return todoItems?.count ?? 1
}

And then your number of rows should be set up like this:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return todoItems[section]?.count ?? 1
}

In order for this to work your todoItems should be array of arrays,

Lu_
  • 2,577
  • 16
  • 24