Home > Net >  Stuck at reassigning TableView Cell property
Stuck at reassigning TableView Cell property

Time:09-23

I really hope someone can help me, I'm stuck at this for 2 days now. Basically I'm working on an App where you can track your reading progress for Books.

The HomeViewController contains a TableView that lists the books you have added. It has a progress Bar and shows what page you're on. The AddBookController is for adding Data about a book that gets delegated to the HomeViewController and is then listed as a TableView Row. The BookDetailController is shown when you select a Row and is for updating the Page you're on. I'll provide some Screenshots so you understand better.

I'm stuck at changing the "currentPage" property of the TableView Cell once you update it in the BookDetailViewController. I'm able to send the updatedPage to the HomeViewController (where the TableView is) but I don't know how to align the values of the Cells with the new value. My idea was to use an didSet-observer but I can't figure out how to set it up the right way.

Here is my Code

HomeViewController

    class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SendingBookDataProtocol {
    
        var updatedPage = String() {
            didSet {    // probably at the wrong place but everything I've tried didn't work
                print(updatedPage)
                tableView?.reloadData()
            }
        }
    
        
        var items = [BookItem]()
        
        var item: BookItem?
    
        override func viewDidLoad() {
            super.viewDidLoad(){
    
            tableView?.delegate = self
            tableView?.dataSource = self
            
            let nib = UINib(nibName: "BookCell", bundle: nil)
            tableView?.register(nib, forCellReuseIdentifier: "BookCell")
    
    }
    
        func sendDataToHomeController(bookEntry item:BookItem) {
            items.append(item)
            tableView.reloadData()
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            items.count
        }
    
      func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
          let bookDetailVc = self.storyboard?.instantiateViewController(withIdentifier: "BookDetailView") as? BookDetailViewController
              let item = items[indexPath.row]
              
              let currentPageInt = Float(item.currentPage)!
              let totalPagesInt = Float(item.totalPages)!
              let result = Int(totalPagesInt - currentPageInt)
              let percentageRead = Int((currentPageInt / totalPagesInt) * 100)
              
            bookDetailVc?.lblName = item.title
            bookDetailVc?.lblCurrentPage = Int(Float(item.currentPage)!)
     // ...some more Code. Basically just sending the Data to BookDetailViewController
       
            self.navigationController!.pushViewController(bookDetailVc!, animated: true)
                                         
      }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "BookCell", for: indexPath) as! BookCell
            item = items[indexPath.row]
        
            cell.title.text = item?.title
    //... and so on
                cell.pageNumbers.text = "S. "   item!.currentPage   " / "   item!.totalPages //here currentPage needs to be updated
                return cell
            }
        }

BookDetailViewController

class BookDetailViewController: HomeViewController, UIPickerViewDelegate, UIPickerViewDataSource{

    @IBOutlet weak var bookTitle: UILabel!
//...
    @IBOutlet weak var numberPicker: UIPickerView!
    
    var lblName = String()
//...
    var lblCurrentPage = Int()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.numberPicker.delegate = self
        self.numberPicker.dataSource = self
//...
}

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {

            let valueSelected = pickerData[row] as String
        
        if let homeVc = storyboard?.instantiateViewController(withIdentifier: "getBookData") as? HomeViewController{
            homeVc.updatedPage = valueSelected
            homeVc.tableView?.reloadData()
        }
     }
    }

AddBookController

protocol SendingBookDataProtocol {
    func sendDataToHomeController(bookEntry: BookItem)
}

struct BookItem {
    let title,author,currentPage,totalPages:String
    let image: UIImage?
}

class AddBookController: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

var delegate: SendingBookDataProtocol? = nil

 @IBAction func buttonSave(_ sender: Any) {

        let bookEntry = BookItem(title: textfieldTitle.text!, author: textfieldAuthor.text!, currentPage: fieldCurrentPage.text!, totalPages: fieldTotalPages.text!, image: bookImage)
        
        self.delegate?.sendDataToHomeController(bookEntry: bookEntry)
                  dismiss(animated: true, completion: nil)
     }
}

// rest should be irrelevant

If anyone could help me on this, I'd be damn grateful. Here are the screenshots

HomeViewController

AddBookController

BookDetailViewController

CodePudding user response:

You have to create a delegate in BookDetailViewController, like this :

protocol BookDetailDelegate: AnyObject {
    func updatePage(for bookItem : BookItem)
}


class BookDetailViewController: HomeViewController, UIPickerViewDelegate, UIPickerViewDataSource {
    var item: BookItem
    var delegate: BookDetailDelegate? 
    //...
    }
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    
       let valueSelected = pickerData[row] as String
       delegate?.updatePage(valueSelected)
     }
}

And then in the HomeViewController:

class HomeViewController {
}
//....
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
          let bookDetailVc = self.storyboard?.instantiateViewController(withIdentifier: "BookDetailView") as? BookDetailViewController
              let item = items[indexPath.row]
            bookDetailVc?.item = item
            bookDetailVc?.delegate = self
       
            self.navigationController!.pushViewController(bookDetailVc!, animated: true)
                                         
      }
//.....

extension HomeViewController: BookDetailDelegate {
    func updatePage(for bookItem: BookItem) {
        let index = item.firstIndex(where: {$0.id = bookItem.id}) //here you should have a UUID or something
        item[index] = bookItem
        tableView.performBatchUpdates({
                self.tableView.reloadRows(at: IndexPath(row: index, section: 0, with: .none)}
            }, completion: nil))
    }
  • Related