Не передаются данные из ViewController в TableViewController

tableviewcontroller
swift

#1

Почему-то теряется значение при попытке передать его из ViewController в TableViewController. Схема вроде простая, значение берется из первого TVC (типа склад) и передается в VC (details), а оттуда в корзину заказа - второй TVC. И при попытке передать в корзину выдает nil, причем именно после сигвея, до него все нормально.

Что здесь не так?

Модель

   struct Bouquet {
        var name: String
    }

Первый TVC

import UIKit

class BouquetsTableViewController: UITableViewController {

var bouquets = [Bouquet]()
var bouquet: Bouquet?

override func viewDidLoad() {
    super.viewDidLoad()
    
    bouquets = [            
        Bouquet(name: "Flower 1"),
        Bouquet(name: "Flower 2"),
        Bouquet(name: "Flower 3"),
        Bouquet(name: "Flower 4"),
        Bouquet(name: "Flower 5"),
        Bouquet(name: "Flower 6")        
}

// MARK: - Table view data source

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

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return bouquets.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "bouquetsCell", for: indexPath)
    cell.textLabel?.text = bouquets[indexPath.row].name
    return cell
}

// MARK: - Navigation   
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    guard segue.identifier == "GoToDetails" else { return }        
    let indexPath = tableView.indexPathForSelectedRow
    bouquet = bouquets[(indexPath?.row)!]        
    let detailsVeiwController = segue.destination as! DetailsViewController        
    detailsVeiwController.bouquet = bouquet        
}

@IBAction func unwindToBouquets(_ unwindSegue: UIStoryboardSegue) {       
}

}

VC

import UIKit
class DetailsViewController: UIViewController {

var bouquet: Bouquet?
var itemToCart = ""

@IBOutlet weak var nameLabel: UILabel!>     

@IBAction func addToCartButton(_ sender: UIButton) {
}

@IBAction func viewCartButton(_ sender: UIButton) {
}

override func viewDidLoad() {
    super.viewDidLoad()        
    nameLabel.text = bouquet?.name
    itemToCart = nameLabel.text!       
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    guard segue.identifier == "addToCart" else { return }        
    let cartTableViewController = segue.destination as! CartTableViewController
    cartTableViewController.cartItem?.name = itemToCart        
}

}

Второй TVC

import UIKit

class CartTableViewController: UITableViewController {

var cartItems = [Bouquet]()
var cartItem: Bouquet?

override func viewDidLoad() {
    super.viewDidLoad()
    
    //print(cartItem)
    cartItems.append(cartItem!)        
}

// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {       
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {        
    return cartItems.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath)
    cell.textLabel?.text = cartItems[indexPath.row].name
    return cell
}

}


#2

вы пытаетесь передать значение в неинициализированный “Bouquet” в третий контроллер. Да и не проще ли передать сам “Bouquet” с VC на ваш третий TVC, а там уже типа такого:

var cartItem: Bouquet? {
    didSet {
        guard let item = cartItem else { return }
        cartItems.append(item)
    }
}

#3

сделал, значение передается. Спасибо за подсказку. Я вообще-то думал, что переменная инициализируется уже в сигвее, когда ей присваивается значение.

Но осталась другая проблема - передается только одно значение. Если затем снова пройти по порядку и выбрать другой элемент, то только он один и показывается в таблице корзины. Чего здесь не хватает?


#4

Здесь не хватает базы, что бы хранить в ней всю корзину. Либо храните это в UserDefaults.


#5

С базой каждый сможет)) А если серьезно, предположим, в этом приложении не нужно сохранять данные в архив на диск, они нужны только во время текущего сеанса. И есть классический пример, когда мы создаем TVC со списком элементов, затем переходим на отдельный экран, где добавляем новое значение и возвращаемся на первый экран, где это значение добавляется в список. И самое главное, что здесь достаточно одной команды append и без всякого сохранения. Т.е. мы можем добавлять сколько угодно новых элементов, они все будут появляться на первом экране в списке пока приложение открыто. Почему же тогда в этом примере. эти новые элементы не сохраняются, ведь структура практически одна и та же, разница только в наличие третьего экрана. Ниже я набросал картинку.

Просто хочется понять, что здесь происходит? Почему при практически одинаковой структуре кода в первом случае все спокойно сохраняется на время текущего сеанса без базы, а во втором это не происходит?


#6

Потому что ваша корзина создается только на 3м TVC и в момент когда вы уходите с него, вся ваша корзина уничтожается в памяти. Делайте тогда либо глобальную корзину (массив я имею в виду), либо синглтон.


#7

Вы конечно правы, но не ясно почему когда юзер уходит с первого TVC, то там данные сохраняются, ведь структурно и там и там все похоже - оба TVC загружаются в память, затем уходят из нее. Но почему третий выгружается полностью, а первый только уходит из фокуса. Скорее всего это связано с иерархией контроллеров, но как это реально происходит?


#8

Почитайте про жизненый цикл. Первый VC не выгружается из памяти, он там остается и все его свойства с данными так же не пропадают.


#9

Ок, спасибо, действительно, первый VC это особый случай, надо еще раз пройтись по жизненному циклу. Может посоветуете какой-то толковый источник?