Ошибка установки текста UILabel в пользовательском UITableViewCell - PullRequest
1 голос
/ 09 апреля 2019

Я довольно новичок в программировании на Swift, но у меня возникают проблемы с настройкой текста UILabel в моем классе UITableView для отдельных экземпляров UITableViewCell.

Я создал собственный подкласс UITableViewCell с именем PizzaTableViewCell и пользовательский UITableViewкласс называется PizzaListTableViewController.Я пытаюсь заполнить экземпляр UITableView данными из массива, который заполняется из вызова API моего сервера node.js.

Я включил свой подкласс UITableView, пользовательский класс UITablveViewCell, структуру дляданные и ссылку на скриншот симулятора, загружающего то, что я сделал.Любая помощь очень ценится!

image

Я проверил, что данные помещаются в массив без проблем, так как я могу напечатать содержимое после вызова fetchInventoryметод.Мне удалось установить один textLabel с

cell.textLabel?.text = pizzas[indexPath.row].name

вместе с изображением в массиве с:

cell.imageView?.image = pizzas[indexPath.row].image

, ноУ меня есть еще 2 метки, которые мне нужны в каждой ячейке, которые я не могу установить.Я проверил свои IBOutlets и идентификаторы раскадровки, и они соответствуют коду.

class PizzaListTableViewController: UITableViewController {

    var pizzas: [Pizza] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        //title you will see on the app screen at the top of the table view
        navigationItem.title = "Drink Selection"

        tableView.register(PizzaTableViewCell.self, forCellReuseIdentifier: "Pizza")
        //tableView.estimatedRowHeight = 134
        //tableView.rowHeight = UITableViewAutomaticDimension

        fetchInventory { pizzas in
            guard pizzas != nil else { return }
            self.pizzas = pizzas!
            print(self.pizzas)
            //self.tableView.reloadData()
            //print(self.pizzas)
            DispatchQueue.main.async { [weak self] in
                self?.tableView.reloadData()
            }
        }

    }   //end of viewDidLoad

    private func fetchInventory(completion: @escaping ([Pizza]?) -> Void) {
        Alamofire.request("http://127.0.0.1:4000/inventory", method: .get)
            .validate()
            .responseJSON { response in
                guard response.result.isSuccess else { return completion(nil) }
                guard let rawInventory = response.result.value as? [[String: Any]?] else { return completion(nil) }
                let inventory = rawInventory.compactMap { pizzaDict -> Pizza? in
                    var data = pizzaDict!
                    data["image"] = UIImage(named: pizzaDict!["image"] as! String)

                    //print(data)
                    //print("CHECK")
                    print("Printing each item: ", Pizza(data: data))
                    //printing all inventory successful

                    return Pizza(data: data)
                }
                completion(inventory)
        }

    }

    @IBAction func ordersButtonPressed(_ sender: Any) {
        performSegue(withIdentifier: "orders", sender: nil)
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    //PRINTING ROWS 0 TWICE in console
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("ROWS", pizzas.count)
        return self.pizzas.count
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell: PizzaTableViewCell = tableView.dequeueReusableCell(withIdentifier: "Pizza", for: indexPath) as! PizzaTableViewCell

        //cell.backgroundColor = Services.baseColor
        //cell.pizzaImageView?.image = pizzas[indexPath.row].image

        //THESE WORK BUT ARE A STATIC WAY OF SETTING THE CELLS
        //CAN ONLY SET THE SELL WITH A SINGLE TEXT LABEL FROM THE DATA ARRAY
        cell.imageView?.image = pizzas[indexPath.row].image
        cell.textLabel?.text = pizzas[indexPath.row].name
        //cell.textLabel?.text = pizzas[indexPath.row].description
        //cell.textLabel?.text = "$\(pizzas[indexPath.row].amount)"


//        cell.name?.text = pizzas[indexPath.row].name
//        cell.imageView?.image = pizzas[indexPath.row].image
//        cell.amount?.text = "$\(pizzas[indexPath.row].amount)"
//        cell.miscellaneousText?.text = pizzas[indexPath.row].description

        //print(cell.name?.text! as Any)
        print(cell.imageView as Any)

        return cell
    }


    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 100.0
    }  //END OF

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        performSegue(withIdentifier: "pizzaSegue", sender: self.pizzas[indexPath.row] as Pizza)
    }  //END OF override func tableView

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "pizzaSegue" {
            guard let vc = segue.destination as? PizzaViewController else { return }
            vc.pizza = sender as? Pizza
        }
    }  //END OF override preppare func

}
class PizzaListTableViewController: UITableViewController {

    var pizzas: [Pizza] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        //title you will see on the app screen at the top of the table view
        navigationItem.title = "Drink Selection"

        tableView.register(PizzaTableViewCell.self, forCellReuseIdentifier: "Pizza")
        //tableView.estimatedRowHeight = 134
        //tableView.rowHeight = UITableViewAutomaticDimension

        fetchInventory { pizzas in
            guard pizzas != nil else { return }
            self.pizzas = pizzas!
            print(self.pizzas)
            //self.tableView.reloadData()
            //print(self.pizzas)
            DispatchQueue.main.async { [weak self] in
                self?.tableView.reloadData()
            }
        }

    }   //end of viewDidLoad

    private func fetchInventory(completion: @escaping ([Pizza]?) -> Void) {
        Alamofire.request("http://127.0.0.1:4000/inventory", method: .get)
            .validate()
            .responseJSON { response in
                guard response.result.isSuccess else { return completion(nil) }
                guard let rawInventory = response.result.value as? [[String: Any]?] else { return completion(nil) }
                let inventory = rawInventory.compactMap { pizzaDict -> Pizza? in
                    var data = pizzaDict!
                    data["image"] = UIImage(named: pizzaDict!["image"] as! String)

                    //print(data)
                    //print("CHECK")
                    print("Printing each item: ", Pizza(data: data))
                    //printing all inventory successful

                    return Pizza(data: data)
                }
                completion(inventory)
        }

    }

    @IBAction func ordersButtonPressed(_ sender: Any) {
        performSegue(withIdentifier: "orders", sender: nil)
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    //PRINTING ROWS 0 TWICE in console
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("ROWS", pizzas.count)
        return self.pizzas.count
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell: PizzaTableViewCell = tableView.dequeueReusableCell(withIdentifier: "Pizza", for: indexPath) as! PizzaTableViewCell

        //cell.backgroundColor = Services.baseColor
        //cell.pizzaImageView?.image = pizzas[indexPath.row].image

        //THESE WORK BUT ARE A STATIC WAY OF SETTING THE CELLS
        //CAN ONLY SET THE SELL WITH A SINGLE TEXT LABEL FROM THE DATA ARRAY
        cell.imageView?.image = pizzas[indexPath.row].image
        cell.textLabel?.text = pizzas[indexPath.row].name
        //cell.textLabel?.text = pizzas[indexPath.row].description
        //cell.textLabel?.text = "$\(pizzas[indexPath.row].amount)"


//        cell.name?.text = pizzas[indexPath.row].name
//        cell.imageView?.image = pizzas[indexPath.row].image
//        cell.amount?.text = "$\(pizzas[indexPath.row].amount)"
//        cell.miscellaneousText?.text = pizzas[indexPath.row].description

        //print(cell.name?.text! as Any)
        print(cell.imageView as Any)

        return cell
    }


    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 100.0
    }  //END OF

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        performSegue(withIdentifier: "pizzaSegue", sender: self.pizzas[indexPath.row] as Pizza)
    }  //END OF override func tableView

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "pizzaSegue" {
            guard let vc = segue.destination as? PizzaViewController else { return }
            vc.pizza = sender as? Pizza
        }
    }  //END OF override preppare func

}
struct Pizza {
    let id: String
    let name: String
    let description: String
    let amount: Float
    //let amount: String
    let image: UIImage

    init(data: [String: Any]) {

        //print("CHECK:: pizza.swift")

        self.id = data["id"] as! String
        self.name = data["name"] as! String

//        self.amount = data["amount"] as! Float
        self.amount = ((data["amount"] as? NSNumber)?.floatValue)!


        self.description = data["description"] as! String
        self.image = data["image"] as! UIImage
    }

}

Как отмечалось выше, я смог напечатать содержимое массива данных с пивомимена, изображения, описания и т. д. Я попытался распечатать на консоли

print(cell.name?.text)

после установки

cell.name?.text = pizzas[indexPath.row].name

, но он печатаетnil и это проблема.Я застрял с этим около 2 недель!

Скриншот IBOutlets:

image

Ответы [ 4 ]

1 голос
/ 10 апреля 2019

Я думаю, что нашел вашу проблему, позвольте мне объяснить

Что вы делаете здесь, у вас есть пользовательский UITableViewCell, определенный в Storyboard в контроллере с именем «Root View Controller», который не являетсяваши PizzaListTableViewController проще говоря

И, как вы сказали, у вас абсолютно нет проблем с IBOutlets

Теперь, когда вы говорите

tableView.register(PizzaTableViewCell.self, forCellReuseIdentifier: "Pizza")

В вашем PizzaListTableViewController вы не связываете его с пользовательским интерфейсом ячейки, а просто с кодом (используется только при отсутствии xib ячейки)

Теперь, что вы можете сделать, чтобы решить эту проблему

Решение # 1

  • Перемещение / копирование вашего пользовательского интерфейса PizzaTableViewCell в PizzaListTableViewController в раскадровке из вашего "Root View Controller"
  • Убедитесь, что вы добавили Reuse Identifier в Инспекторе атрибутов ячейки в раскадровке
  • remove tableView.register(PizzaTableViewCell.self, forCellReuseIdentifier: "Pizza") на этот раз вы не получите ошибку, поскольку она автоматически получит регистр
  • Убедитесь, что все IBOutlets подключены

Решение # 2

создайте отдельную Nib (xib) ячейки, и теперь вам нужно зарегистрировать ячейку здесь, как

tableView.register(UINib(nibName: "PizzaTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: "PizzaCell")

Надеюсь, это поможет.

0 голосов
/ 10 апреля 2019

Убедитесь, что ваш класс Table View Controller установлен в раскадровке.

Убедитесь, что в раскадровке установлен класс ячейки табличного представления.

enter image description here

Убедитесь, что все ваши розетки правильно подключены.

enter image description here

Убедитесь, что ваш идентификатор ячейки табличного представления указан в раскадровке.

enter image description here

Подкласс контроллера вида My Table

enter image description here

Подкласс ячеек представления моей таблицы

cell.imageView? .Image и cell.textLabel? .Text являются необязательными свойствами самого табличного представления. Они не являются свойствами созданной вами пользовательской ячейки.

Вы используете tableView.register (PizzaTableViewCell.self, forCellReuseIdentifier: "Pizza") , когда вы создали ячейку табличного представления в XIB. Но так как вы разработали ячейку в самой раскадровке, вы должны установить идентификатор повторного использования ячейки и класс ячейки в раскадровке.

Надеюсь, это вам поможет.

0 голосов
/ 09 апреля 2019

enter image description here

Что-то определенно странное происходит с вашей настройкой.Если вы попытаетесь присвоить IBOutlets то же имя, что и у свойства по умолчанию UITableViewCell, произойдет ошибка.Тот факт, что вы смогли установить эти имена и успешно выполнить сборку, странный.

На приведенном выше снимке экрана видно, что происходит, когда я пытался это сделать.

0 голосов
/ 09 апреля 2019

Попробуйте это

cell.name?.text = ...
cell.amount?.text = ...
cell.miscellaneousText?.text = ...
cell.pizzaImageView?.image = ...

Если это все еще не работает, убедитесь, что ваша ячейка и ваши розетки не равны нулю при установке его значения.Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...