В чем разница между UIStackView и UITableView в UIKit?

Ответ

UIStackView — это контейнер для компоновки (layout), который автоматически управляет расположением своих дочерних вью по горизонтали или вертикали.

UITableView — это вид для отображения прокручиваемых списков данных, оптимизированный для работы с большими наборами элементов.

Сравнительная таблица

Характеристика UIStackView UITableView
Основное назначение Управление layout статичного набора вью Отображение динамических, прокручиваемых списков данных
Скроллинг Не поддерживает. Для скролла нужно поместить в UIScrollView. Нативная поддержка вертикального (и горизонтального) скролла.
Оптимизация памяти Нет. Все дочерние вью загружаются сразу. Есть. Механизм переиспользования ячеек (dequeueReusableCell).
Структура данных Простая линейная (массив arrangedSubviews). Сложная (секции, строки, заголовки, футеры).
Динамическое изменение Легко добавлять/удалять вью, анимация распределения. Требует обновления данных через insertRows, deleteRows и т.д.

Пример использования UIStackView

// Создание вертикального стека с отступами
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 10
stackView.alignment = .fill
stackView.distribution = .fillEqually

// Добавление вью
let label = UILabel()
label.text = "Заголовок"
let button = UIButton(type: .system)
button.setTitle("Кнопка", for: .normal)

stackView.addArrangedSubview(label)
stackView.addArrangedSubview(button)

// Для скролла помещаем стек в UIScrollView
let scrollView = UIScrollView()
scrollView.addSubview(stackView)
// ... настройка constraints для stackView внутри scrollView

Пример использования UITableView

class MyViewController: UIViewController, UITableViewDataSource {
    let tableView = UITableView()
    let data = ["Элемент 1", "Элемент 2", "Элемент 3"]

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        tableView.dataSource = self
        view.addSubview(tableView)
        // ... настройка frame/constraints
    }

    // Обязательный метод data source
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }

    // Обязательный метод data source с переиспользованием ячейки
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        cell.textLabel?.text = data[indexPath.row]
        return cell // Ячейка конфигурируется и возвращается
    }
}

Когда что использовать?

  • UIStackView: Для статичных форм, групп кнопок, вертикальных/горизонтальных блоков интерфейса, где элементы известны на этапе компиляции.
  • UITableView: Для отображения списков контактов, лент новостей, любых данных, количество которых может меняться и потенциально велико.

Ответ 18+ 🔞

А, слушай, смотри, вот эта дилемма — UIStackView против UITableView — она у начинающих вообще мозг в труху превращает, блядь. Сейчас разложу по полочкам, чтобы ты не путался, как последний распиздяй.

UIStackView — это, по сути, тупой, но гениальный контейнер-распределитель. Как тот самый здоровенный немой Герасим из рассказа, только вместо собаки Муму у него вьюхи. Он их тупо по порядку расставляет — либо в линеечку (горизонтально), либо в столбик (вертикально). И всё, блядь. Больше от него нихуя не добьёшься. Он тупо держит, распределяет и всё.

UITableView — это уже целый ёперный театр с декорациями, сука. Это не просто контейнер, а целая система для показа прокручиваемых списков, где данных может быть овердохуища. У него там свои законы, секции, ячейки, которые переиспользуются, чтобы память не жрать как не в себя.

Короче, смотри таблицу, чтобы не быть мудаком:

Что сравниваем UIStackView UITableView
Зачем он, блядь? Чтобы аккуратно разложить известные вьюхи. Чтобы показать список, который может тянуться до хуя и обратно.
Скроллит сам? Не, нихуя. Сам — нет. Только если в UIScrollView засунешь, тогда да. Ага, вот это да! Сам скроллит, как по маслу.
Память жрёт? Жрёт всё сразу, что в него сунешь. Хитрожопый! Переиспользует ячейки, чтобы не грузить всё за раз.
Структура Проще некуда — массив arrangedSubviews. Замудрённая — секции, строки, индексы, ёб твою мать.
Динамика Легко добавить/удалить вьюху, анимация из коробки. Надо танцевать с бубном: beginUpdates, insertRows, пиздец.

Пример: когда ты Герасим с вьюхами (UIStackView)

Допустим, тебе надо сделать блок с заголовком, картинкой и кнопкой. Вот твой инструмент.

// Делаем вертикальный стек, как паровоз
let stack = UIStackView()
stack.axis = .vertical // Ставим в столбик
stack.spacing = 8 // Отступ между ними
stack.alignment = .fill // Чтобы растягивались
stack.distribution = .fill // Распределение

// Лепим в него что душе угодно
let titleLabel = UILabel()
titleLabel.text = "Заголовок, мать его"

let imageView = UIImageView()
imageView.image = UIImage(named: "kartinka")

let actionButton = UIButton(type: .system)
actionButton.setTitle("Жми сюда, не ссы", for: .normal)

// Добавляем в стек — он сам всё расставит
stack.addArrangedSubview(titleLabel)
stack.addArrangedSubview(imageView)
stack.addArrangedSubview(actionButton)

// Хочешь скроллить? Засунь этот стек в UIScrollView, делов-то.

Пример: когда данных дохуя и они в списке (UITableView)

А вот тут уже история посерьёзнее. Готовься конформиться протоколам.

class MyListController: UIViewController, UITableViewDataSource {
    let table = UITableView()
    // Допустим, данные — это массив строк. В жизни может быть что угодно.
    let myData = ["Первая строка", "Вторая", "Третья", "И так дохуя"]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Регистрируем тип ячейки, которую будем переиспользовать
        table.register(UITableViewCell.self, forCellReuseIdentifier: "StandartCell")
        table.dataSource = self // Говорим: "Слушай сюда, данные брать у меня!"
        view.addSubview(table)
        // ... Не забудь constraints или frame задать, а то нихуя не увидишь
    }

    // Спросят: "А строк сколько, блядь?" — отвечай:
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myData.count // Вот столько, сука
    }

    // А тут уже давай каждую ячейку конфигурируй
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // Магия переиспользования! Не создаём новую, а берём старую, если она за экраном.
        let cell = tableView.dequeueReusableCell(withIdentifier: "StandartCell", for: indexPath)
        // Достаём нужную строку данных
        let textForThisRow = myData[indexPath.row]
        // Пихаем текст в ячейку
        cell.textLabel?.text = textForThisRow
        return cell // И отправляем на показ
    }
}

Итог, чтобы не быть мудаком:

  • Берёшь UIStackView, когда у тебя интерфейс статичный, вьюх немного и они все на экране помещаются. Типа формы, панельки с кнопками. Просто, как три копейки.
  • Берёшь UITableView, когда данных неведомо сколько, они приходят с сервера, их надо скроллить и не угробить приложение. Списки, ленты, таблицы — его царство.

Всё, теперь ты в теме. Не путай, а то получится пиздопроебибна, а не интерфейс.