Search code examples
iosswiftswift4swift5

Im getting an error at cellForRowAt and im not sure why


I am getting an error in the function cellForRowAt

Cannot assign value of type 'Product' to type 'String?'

Is cell.textLabel?.text = product the issue that's causing this error?

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        let product = items[indexPath.row]
        cell.textLabel?.text = product

        cell.contentView.backgroundColor = UIColor(red:0.92, green:0.92, blue:0.92, alpha:1.0)
        cell.textLabel?.textColor = UIColor(red:0.13, green:0.13, blue:0.13, alpha:1.0)
        tableView.separatorColor = UIColor(red:0.13, green:0.13, blue:0.13, alpha:1.0)


        return cell
    }

Solution

  • cell.textLabel?.text can only show a String object, not other objects.

    It will be product.item or product.price or product.salesPrice or all in one line. (based on your requirement).

    Make sure the value of product is not nil.

    cell.textLabel?.text = "\(product.item) \(product.price) \(product.salesPrice)"
    

    The full code you can try this:

    class ViewController: UIViewController, UIAdaptivePresentationControllerDelegate {
    
        @IBOutlet weak var tableView: UITableView!
    
        var items:[Product]? = []
    
        // VIEW LOAD
        override func viewDidLoad() {
            super.viewDidLoad()
    
            if #available(iOS 13.0, *) {
                self.isModalInPresentation = true
            }
    
            getData()
        }
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(true)
            getData()
        }
    
        override func viewDidDisappear(_ animated: Bool) {
            super.viewDidDisappear(true)
            storeData()
        }
        override var prefersStatusBarHidden: Bool {
            return true
        }
        // ADD ITEMS
        @IBAction func addButtonTapped(_ sender: Any) {
            let alert = UIAlertController(title: "Product Information", message: nil, preferredStyle: .alert)
            alert.addTextField { (itemTextField) in
                itemTextField.placeholder = "Item"
            }
            alert.addTextField { (priceTextField) in
                priceTextField.placeholder = "Price"
            }
    
            alert.addTextField { (salePriceTextField) in
                salePriceTextField.placeholder = "Sale Price"
            }
    
            let action = UIAlertAction(title: "Add", style: .default) { (_) in
                let item = alert.textFields?[0].text ?? ""
                let price = alert.textFields?[1].text ?? ""
                let salesPrice = alert.textFields?[2].text ?? ""
    
                let product = Product(item: item, price: price, salesPrice: salesPrice)
                self.addProduct(product)
            }
    
            alert.addAction(action)
            present(alert, animated: true)
            storeData()
    
        }
    
        func addProduct(_ product: Product) {
            let index = 0
            items?.insert(product, at: index)
    
            let indexPath = IndexPath(row: index, section: 0)
            tableView.insertRows(at: [indexPath], with: .left)
            storeData()
        }
    
        //STORE DATA
        func storeData() {
            UserDefaultUtil.saveData(products: items)
        }
    
        func getData() {
            items = UserDefaultUtil.loadProducts()
    
        }
    
    }
    
    //EXTENSION
    extension ViewController: UITableViewDataSource {
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return items!.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = UITableViewCell()
            let product = items![indexPath.row]
            cell.textLabel?.text = "\(product.item!) \(product.price) \(product.salesPrice)"
    
            cell.contentView.backgroundColor = UIColor(red:0.92, green:0.92, blue:0.92, alpha:1.0)
            cell.textLabel?.textColor = UIColor(red:0.13, green:0.13, blue:0.13, alpha:1.0)
            tableView.separatorColor = UIColor(red:0.13, green:0.13, blue:0.13, alpha:1.0)
    
    
            return cell
        }
    
        func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
            guard editingStyle == .delete else { return }
            items?.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .fade)
            storeData()
        }
    }
    
    class UserDefaultUtil {
    
        private static let Key = "savedData"
    
        private static func archivePeople(people : [Product]) -> NSData {
    
            return NSKeyedArchiver.archivedData(withRootObject: people as NSArray) as NSData
        }
    
        static func loadProducts() -> [Product]? {
    
            if let unarchivedObject = UserDefaults.standard.object(forKey: Key) as? Data {
    
                return NSKeyedUnarchiver.unarchiveObject(with: unarchivedObject as Data) as? [Product]
            }
    
            return nil
        }
    
        static func saveData(products : [Product]?) {
            let archivedObject = archivePeople(people: products!)
            UserDefaults.standard.set(archivedObject, forKey: Key)
            UserDefaults.standard.synchronize()
        }
    
    }
    
    class Product: NSObject, NSCoding {
        var item: String?
        var price: String?
        var salesPrice: String?
    
        required init(item:String, price:String, salesPrice: String) {
            self.item = item
            self.price = price
            self.salesPrice = salesPrice
        }
    
        required init(coder aDecoder: NSCoder) {
            self.item = aDecoder.decodeObject(forKey: "item") as? String
            self.price = aDecoder.decodeObject(forKey: "price") as? String
            self.salesPrice = aDecoder.decodeObject(forKey: "salesPrice") as? String
        }
    
        public func encode(with aCoder: NSCoder) {
            aCoder.encode(item, forKey: "item")
            aCoder.encode(price, forKey: "price")
            aCoder.encode(salesPrice, forKey: "salesPrice")
        }
    }