В чем разница между UITableView и UICollectionView?

Ответ

UITableView — компонент для отображения одно- или многосекционных вертикальных списков. UICollectionView — гибкий компонент для отображения данных в произвольных макетах.

Сравнительный анализ:

Характеристика UITableView UICollectionView
Макет по умолчанию Вертикальный список, 1 колонка Сетка (flow layout) или кастомный
Ориентация Только вертикальная Любая (через scrollDirection)
Ячейки UITableViewCell со стандартными стилями UICollectionViewCell полностью кастомные
Заголовки/подвалы tableHeaderView, tableFooterView, секционные Supplementary views через UICollectionReusableView
Делегат UITableViewDelegate UICollectionViewDelegate
Источник данных UITableViewDataSource UICollectionViewDataSource
Анимации Встроенные для строк Кастомные через UICollectionViewLayout
Переиспользование dequeueReusableCell(withIdentifier:) dequeueReusableCell(withReuseIdentifier:for:)

Пример UITableView:

class SimpleListVC: UIViewController, UITableViewDataSource {
    let tableView = UITableView()

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        tableView.dataSource = self
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        cell.textLabel?.text = "Row (indexPath.row)"
        return cell
    }
}

Пример UICollectionView с кастомным макетом:

class GridVC: UIViewController, UICollectionViewDataSource {
    let layout: UICollectionViewFlowLayout = {
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: 100, height: 100)
        layout.minimumLineSpacing = 10
        layout.minimumInteritemSpacing = 5
        layout.scrollDirection = .vertical
        layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        return layout
    }()

    lazy var collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)

    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "Cell")
        collectionView.dataSource = self
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 20
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CustomCell
        cell.configure(with: indexPath)
        return cell
    }
}

Рекомендации по выбору:

  • Используйте UITableView для:

    • Простых списков (настройки, меню)
    • Мастер-деталь интерфейсов
    • Когда нужны стандартные стили ячеек (.subtitle, .value1)
  • Используйте UICollectionView для:

    • Сеток фотографий
    • Горизонтальных каруселей
    • Кастомных макетов (Pinterest-style, staggered grid)
    • Анимированных переходов между layout
    • Когда нужны сложные supplementary views

Производительность:

  • Оба компонента эффективно переиспользуют ячейки
  • UICollectionView может быть медленнее при сложных layout вычислениях
  • Для больших наборов данных используйте prefetching (UITableViewDataSourcePrefetching, UICollectionViewDataSourcePrefetching)

Ответ 18+ 🔞

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

Так, смотри. Есть у нас UITableView — это, можно сказать, классика жанра, столп и опора. Он умеет делать одно: вертикальный список, одна колонка, всё ровно, как под линеечку. Как будто бы твоя бабушка перечисляет, что купить в магазине на бумажке. Просто, понятно, без выебонов.

А есть UICollectionView — это уже, сука, полный разгул фантазии. Хочешь — сетку фоток сделай, хочешь — горизонтальную карусель, хочешь — разбросай ячейки по экрану в стиле «пьяный дизайнер». Это как конструктор «Лего» против простых кубиков.

Краткая сводка, чтобы не еб@ть мозг:

Критерий UITableView UICollectionView
Как выглядит Вертикальный список, один столбец Да что угодно! Сетка, карусель, абстракция.
Крутить можно? Только сверху вниз Куда захочешь, хоть по диагонали (шучу, но почти).
Ячейки Есть готовые стили (с подзаголовком, с картинкой) Делай сам с нуля, как художник.
Шапки и подвалы Есть простые для всей таблицы и для секций Есть, но через supplementary views — чуть сложнее.
Кто управляет? UITableViewDelegate и UITableViewDataSource UICollectionViewDelegate и UICollectionViewDataSource (логично, да?)
Анимации Встроенные для добавления/удаления строк Мощные, через кастомные лейауты — можно творить магию.
Как ячейки берем? dequeueReusableCell(withIdentifier:) dequeueReusableCell(withReuseIdentifier:for:) (чуть длиннее, блядь).

Вот тебе пример UITableView, проще пареной репы:

class SimpleListVC: UIViewController, UITableViewDataSource {
    let tableView = UITableView()

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        tableView.dataSource = self
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        cell.textLabel?.text = "Row (indexPath.row)"
        return cell
    }
}

Видишь? Зарегистрировал, написал два метода — и готово, список торчит. Никакой ебли.

А вот UICollectionView уже посерьёзнее, с кастомной сеткой:

class GridVC: UIViewController, UICollectionViewDataSource {
    let layout: UICollectionViewFlowLayout = {
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: 100, height: 100)
        layout.minimumLineSpacing = 10
        layout.minimumInteritemSpacing = 5
        layout.scrollDirection = .vertical
        layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        return layout
    }()

    lazy var collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)

    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "Cell")
        collectionView.dataSource = self
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 20
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CustomCell
        cell.configure(with: indexPath)
        return cell
    }
}

Тут уже нужно лейаут настраивать — размеры ячеек, отступы, направление скролла. Но зато и возможности — овердохуища!

Так что когда что брать?

Тащи UITableView, если:

  • Делаешь простой список настроек, типа «Звук», «Уведомления», «О приложении».
  • Нужен стандартный мастер-деталь интерфейс (список контактов -> детали контакта).
  • Лень заморачиваться — нужны готовые стили ячеек (.subtitle, .value1). Работает из коробки, ёпта!

Врубай UICollectionView, если:

  • Делаешь галерею или сетку фоток (как в Instagram).
  • Нужна горизонтальная карусель товаров или баннеров.
  • Хочется выебистый макет в стиле Pinterest, где ячейки разной высоты.
  • Планируешь анимированные переходы между разными раскладками.
  • Нужны сложные дополнительные view (шапки, подвалы, фоны для секций), которые не влезают в простые рамки.

По производительности: Оба, блядь, молодцы — ячейки переиспользуют, как заправские скряги. Но UICollectionView может начать подтупливать, если у тебя лейаут с хуёвиной логикой расчётов на каждую ячейку. Для огромных списков в обоих случаях юзай prefetching (UITableViewDataSourcePrefetching или UICollectionViewDataSourcePrefetching), чтобы подгружать данные заранее и не ждать, пока пользователь доскроллит и пошлёт тебя нахуй из-за лагов.

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