UITableView: mga batayan, listahan at cell sa mga iOS app

May-akda: IT Sectr Nai-publish: 2026-02-23 Oras ng pagbabasa: 9 min

UITableView — ang pangunahing bahagi ng UIKit para sa pagpapakita ng mga vertical na listahan sa iOS. Ang bawat hilera ng talahanayan ay isang UITableViewCell cell na may paunang natukoy na mga estilo. Ipinapaliwanag namin ang mga batayan ng UITableView: DataSource, delegado, muling paggamit ng mga cell, at pagganap ng mga talahanayan sa mga iOS app. Ayon sa Apple (Human Interface Guidelines, 2026), ang UITableView ay nananatiling pinaka-ginagamit na bahagi ng UI sa iOS — 85% ng mga top-100 App Store app ay naglalaman ng kahit isang talahanayan. Para sa mga kumplikadong layout, basahin ang artikulo tungkol sa UICollectionView.

Mga pangunahing punto

  • UITableView — bahagi ng UIKit para sa mga vertical na listahan, available mula noong iOS 2.0 (iPhone OS 2).
  • UITableViewCell — cell ng talahanayan na may apat na built-in na estilo at kakayahang mag-customize.
  • UITableViewDataSource — protokol na tumutukoy sa bilang ng mga hilera at cell para sa bawat seksyon.
  • UITableViewDelegate — protokol para sa paghawak ng pagpili, pag-edit, at pagtatakda ng taas ng hilera.
  • UITableViewDiffableDataSource — modernong DataSource (iOS 13+) na may awtomatikong pagkalkula ng mga pagbabago.

Ano ang UITableView sa iOS?

UITableView — ay isang klase mula sa framework ng UIKit na idinisenyo para sa pagpapakita ng nai-scroll na listahan ng mga hilera sa isang kolum. Ang bawat hilera ay kinakatawan ng isang UITableViewCell object. Lumitaw ang UITableView sa iPhone OS 2 (2008) at mula noon ay nananatiling pangunahing bahagi para sa mga listahan sa iOS. Ang arkitektura ng UITableView ay binuo sa pattern ng MVC: ang data ay pinamamahalaan ng DataSource, ang hitsura at pag-uugali ng Delegate, at ang view ng talahanayan mismo.

Dalawang estilo ng talahanayan: .plain (tuloy-tuloy na listahan na may opsyonal na mga seksyon) at .grouped (mga pinagsama-samang seksyon na may bilugan na mga sulok at margin). Mula noong iOS 13, idinagdag ang .insetGrouped — grouped-style na may margin mula sa mga gilid, ginagamit sa mga app na Mga Setting at Kalusugan. Ang pagpili ng estilo ay nakakaapekto sa default na hitsura: ang mga plain-table ay nagdidikit ng header ng seksyon sa itaas habang nag-scroll (sticky header), grouped — hindi.

Self-Sizing Cells

Mula noong iOS 8, sinusuportahan ng UITableView ang mga cell na may awtomatikong laki (self-sizing cells). Upang i-activate, itakda ang tableView.estimatedRowHeight (hal. 80) at tableView.rowHeight = UITableView.automaticDimension. Awtomatikong kinakalkula ng talahanayan ang taas ng hilera batay sa mga constraint ng Auto Layout sa loob ng cell. Binabawasan ng self-sizing ang pagganap para sa mga kumplikadong cell — gumamit ng nakapirming taas (rowHeight) para sa mga talahanayan na may 500+ elemento.

Mga estilo ng UITableViewCell: basic, subtitle, value1, value2

UITableViewCell ay nagbibigay ng apat na built-in na estilo na sumasaklaw sa 80% ng mga senaryo nang hindi nangangailangan na lumikha ng custom na cell. Ang bawat estilo ay binubuo ng kumbinasyon ng textLabel, detailTextLabel at imageView. Ang pagpili ng estilo ay itinakda sa pagsisimula ng cell sa pamamagitan ng init(style:reuseIdentifier:).

EstilotextLabeldetailTextLabelimageViewHalimbawa
.default (.basic)Kaliwa, boldWalaOpsyonalMenu, listahan ng item
.subtitleKaliwa, boldSa ilalim ng textLabel, kulay-aboOpsyonalMga contact, playlist
.value1Kaliwa, boldKanan, kulay-aboWalaMga setting na may halaga
.value2Kanan, asulKaliwa, kulay-aboWalaAklat ng telepono (iOS 6 na estilo)
swift
// Paggawa ng talahanayan na may custom na mga cell
class ContactListController: UIViewController {

    private let tableView = UITableView(frame: .zero, style: .insetGrouped)

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        tableView.dataSource = self
        tableView.delegate = self
        tableView.rowHeight = 60
        view.addSubview(tableView)

        // Auto Layout
        tableView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.topAnchor),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }
}

extension ContactListController: UITableViewDataSource {

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

    func tableView(_ tableView: UITableView,
                         cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let contact = contacts[indexPath.row]

        var content = cell.defaultContentConfiguration()
        content.text = contact.name
        content.secondaryText = contact.phone
        content.image = UIImage(systemName: "person.circle")
        cell.contentConfiguration = content

        return cell
    }
}

UIContentConfiguration (iOS 14+) — modernong paraan ng pag-configure ng mga cell sa pamamagitan ng contentConfiguration sa halip na direktang pag-access sa textLabel/detailTextLabel. Gamitin ang cell.defaultContentConfiguration() o lumikha ng custom na UIContentConfiguration. Mga kalamangan: suporta para sa dynamic na uri, madilim na tema, at VoiceOver agad. Inirerekomenda ng Apple (WWDC 2024) ang contentConfiguration para sa lahat ng bagong UITableView.

DataSource at Delegate: mga sapilitang pamamaraan

UITableViewDataSource — protokol na nagbibigay ng data para sa talahanayan. Mga sapilitang pamamaraan: tableView(_:numberOfRowsInSection:) at tableView(_:cellForRowAt:). Kung wala sila, hindi maaaring magpakita ang talahanayan ng anumang hilera. UITableViewDelegate — protokol para sa pamamahala ng hitsura at pag-uugali: taas ng hilera, pagpili, pag-edit, contextual actions.

swift
// Halimbawa na may maraming seksyon at pag-edit
extension ContactListController: UITableViewDelegate {

    // Custom na taas para sa bawat hilera
    func tableView(_ tableView: UITableView,
                         heightForRowAt indexPath: IndexPath) -> CGFloat {
        80
    }

    // Paghawak ng pagpili
    func tableView(_ tableView: UITableView,
                         didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        let contact = contacts[indexPath.row]
        showDetail(for: contact)
    }

    // Mag-swipe upang tanggalin
    func tableView(_ tableView: UITableView,
                         trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath)
        -> UISwipeActionsConfiguration? {
        let deleteAction = UIContextualAction(style: .destructive, title: "Tanggalin") {
            [weak self] _, _, completion in
            self?.contacts.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .automatic)
            completion(true)
        }
        return UISwipeActionsConfiguration(actions: [deleteAction])
    }
}

Pagganap ng Delegate: ang mga pamamaraan ng laki (heightForRowAt) ay tinatawag para sa bawat nakikitang hilera sa bawat pag-scroll. Para sa pare-parehong taas, itakda nang direkta ang rowHeight — ito ay 10 beses na mas mabilis kaysa sa heightForRowAt. Para sa self-sizing cell, itakda ang estimatedRowHeight at automaticDimension — tatawagin ng talahanayan ang heightForRowAt lamang para sa mga nakikitang hilera, at gagamitin ang estimatedRowHeight para sa iba.

Muling paggamit ng cell: reuse queue at register

Reuse queue — pool ng mga reusable na UITableView cell. Kapag ang isang cell ay umalis sa screen, hindi ito tinatanggal ngunit inilalagay sa pila. Ang mga bagong cell ay hindi nilikha mula sa simula — ang system ay tumatawag ng dequeueReusableCell(withIdentifier:for:), na nagbabalik ng cell mula sa pila o lumikha ng bago kung ang pila ay walang laman. Ito ang pangunahing mekanismo ng pagganap ng UITableView.

swift
// Custom na cell na may caching
class ContactCell: UITableViewCell {

    private let avatarView = UIImageView()
    private let nameLabel = UILabel()
    private let subtitleLabel = UILabel()

    override init(style: UITableViewCell.Style, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupViews()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setupViews() {
        contentView.addSubview(avatarView)
        contentView.addSubview(nameLabel)
        contentView.addSubview(subtitleLabel)

        // Pag-configure ng Auto Layout constraints
        avatarView.translatesAutoresizingMaskIntoConstraints = false
        // ... constraints ...
    }

    func configure(with contact: Contact) {
        nameLabel.text = contact.name
        subtitleLabel.text = contact.phone
        // Asynchronous na pag-load ng avatar
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        avatarView.image = nil
        nameLabel.text = nil
        subtitleLabel.text = nil
    }
}

// Pagrehistro at paggamit
tableView.register(ContactCell.self, forCellReuseIdentifier: "contactCell")

// Sa cellForRowAt:
let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactCell
cell.configure(with: contacts[indexPath.row])
return cell

prepareForReuse() — pamamaraan na tinatawag bago ilagay ang cell sa reuse queue. I-reset ang buong estado ng cell: teksto, mga imahe, animation, pag-load. Kung walang prepareForReuse, ang isang reused cell ay maaaring magpakita ng lumang data: ang nakaraang imahe ay makikita sa isang bahagi ng isang segundo hanggang sa ma-load ang bago. Inirerekomenda ng Apple (WWDC 2023) ang paglilinis ng mga asynchronous na operasyon sa pamamagitan ng URLSessionTask.cancel() sa prepareForReuse.

Mga seksyon, header at footer: pagpapangkat ng data

Mga seksyon sa UITableView ay nagpapangkat ng mga lohikal na nauugnay na hilera. Ang bawat seksyon ay maaaring magkaroon ng header (pamagat) at footer (paa). Ang bilang ng mga seksyon ay tinutukoy ng pamamaraang numberOfSections(in:) (default 1). Para sa grouped at insetGrouped na mga estilo, ang mga seksyon ay biswal na pinaghihiwalay ng mga margin at bilugan na sulok.

DataSource na pamamaraanPaglalarawanHalaga ng pagbabalik
numberOfSectionsBilang ng mga seksyon (default 1)Int
numberOfRowsInSectionBilang ng mga hilera sa seksyonInt
titleForHeaderInSectionTeksto ng pamagat ng seksyonString?
titleForFooterInSectionTeksto ng paa ng seksyonString?
viewForHeaderInSectionCustom na view para sa headerUIView?
heightForHeaderInSectionTaas ng headerCGFloat

Pag-index: para sa mabilis na pag-navigate sa mga seksyon, magdagdag ng index — array ng mga string na ipinapakita sa kanan. Ipatupad ang sectionIndexTitles(for:) — nagbabalik ng array ng mga unang titik ng bawat seksyon. Para sa 26+ na seksyon, ito ay kritikal na nagpapabuti sa UX. Sa iOS 15+, sinusuportahan ng mga talahanayan ang sectionHeaderTopPadding — ang puwang sa pagitan ng status bar at unang header na maaaring i-reset sa 0 para sa compact na layout.

Pagganap ng UITableView: pinakamahusay na kasanayan

Pagganap ng UITableView ay kritikal para sa mga app na may mahabang listahan. Mga pangunahing problema: mabagal na pag-scroll (jank) dahil sa mabibigat na operasyon sa cellForRowAt, madalas na tawag sa heightForRowAt, kawalan ng prefetching. Itinatampok ng Apple (WWDC 2025) ang limang pangunahing kasanayan para sa mga talahanayan na may 1000+ elemento.

  • Flat-height — gumamit ng pare-parehong rowHeight sa halip na heightForRowAt para sa lahat ng cell. Pagkakaiba: 60 FPS vs 30 FPS para sa isang talahanayan na may 500 hilera.
  • Prefetching — ipatupad ang UITableViewDataSourcePrefetching para sa asynchronous na pag-load ng data (mga imahe, API) bago lumitaw ang cell sa screen.
  • Mas kaunting subview — bawat subview sa contentView ay nagpapataas ng oras ng pag-render. Gumamit ng draw() para sa simpleng graphics (mga separator, icon) sa halip na UIImageView.
  • Mabibigat na operasyon sa background — gawin ang pag-format ng petsa, lokalisasyon, pagkalkula sa modelo, hindi sa cellForRowAt. Gumamit ng NSCache para sa mga resulta.
  • DiffableDataSource — palitan ang reloadData() ng apply(snapshot) — ang animation ay nangyayari nang libre, ang talahanayan ay hindi ganap na na-reload.
swift
// Pag-optimize gamit ang prefetching
extension ContactListController: UITableViewDataSourcePrefetching {

    func tableView(_ tableView: UITableView,
                         prefetchRowsAt indexPaths: [IndexPath]) {
        for indexPath in indexPaths {
            let contact = contacts[indexPath.row]
            ImageCache.shared.prefetch(url: contact.avatarUrl)
        }
    }

    func tableView(_ tableView: UITableView,
                         cancelPrefetchingForRowsAt indexPaths: [IndexPath]) {
        for indexPath in indexPaths {
            let contact = contacts[indexPath.row]
            ImageCache.shared.cancelPrefetch(url: contact.avatarUrl)
        }
    }
}

// Paggamit ng DiffableDataSource para sa maayos na mga update
class ModernTableController: UIViewController {

    private var dataSource: UITableViewDiffableDataSource<Section, Contact>!

    func applyContacts(_ contacts: [Contact]) {
        var snapshot = NSDiffableDataSourceSnapshot<Section, Contact>()
        snapshot.appendSections([.main])
        snapshot.appendItems(contacts)
        dataSource.apply(snapshot, animatingDifferences: true)
    }
}

Praktikal na resulta: ang paglalapat ng mga optimisasyong ito ay nagpapataas ng scroll FPS mula 30 hanggang 60 sa mga iPhone 12 at mas lumang device (ayon sa mga pagsubok ng Apple, 2025). Sa mga proyekto ng IT Sectr, ginagamit namin ang DiffableDataSource para sa lahat ng bagong talahanayan at nagdaragdag ng prefetching para sa mga talahanayan na may mga imahe (avatar, preview, icon ng app).

Mga madalas itanong

Ang UITableView ay hindi nag-scroll — ano ang gagawin?

Suriin: (1) contentSize > frame.size — ang talahanayan ay dapat may higit na nilalaman kaysa sa taas nito; (2) ang talahanayan ay wala sa loob ng isa pang UIScrollView na humaharang ng mga kilos; (3) isScrollEnabled = true; (4) ang numberOfRowsInSection ay nagbabalik ng tamang bilang. Karaniwang problema — isang talahanayan na may heightForRowAt = UITableView.automaticDimension na walang estimatedRowHeight, na humahantong sa walang katapusang pagkalkula ng taas.

Paano i-update ang UITableView nang hindi kumukurap?

Gumamit ng performBatchUpdates o DiffableDataSource sa halip na reloadData(). Ang reloadData() ay nagdudulot ng kumpletong pag-reload nang walang animation, na lumilikha ng visual na pagkurap. Para sa point update, gamitin ang: reloadRows(at:with:), insertRows, deleteRows. Lahat ng pagbabago sa loob ng performBatchUpdates ay sabay na nai-animate. Ginagawa ito ng DiffableDataSource nang awtomatiko nang walang manu-manong tawag.

Ano ang pagkakaiba sa pagitan ng UITableView at UICollectionView?

UITableView — isang-kolum na vertical na listahan na may paunang natukoy na mga estilo ng cell at built-in na pag-edit. UICollectionView — flexible na layout (grid, listahan, carousel, cascade) na may arbitraryong paglalagay ng mga elemento. Piliin ang UITableView para sa mga simpleng listahan (mga setting, contact, mensahe). Piliin ang UICollectionView para sa mga gallery, katalogo, board, at anumang non-linear na layout.

Paano alisin ang mga walang laman na hilera sa ilalim ng nilalaman sa UITableView?

Itakda ang tableView.tableFooterView = UIView(frame: .zero). Bilang default, ang UITableView ay nagpapakita ng mga walang laman na hilera (mga separator) sa ilalim ng huling elemento hanggang sa ibabang gilid. Ang pagtatakda ng walang laman na UIView sa tableFooterView ay nag-aalis sa kanila. Para sa grouped-style, hindi ito kinakailangan — ang talahanayan ay nagpapakita lamang ng mga aktwal na hilera na may bilugan na sulok ng huling seksyon.

Paano gumawa ng UITableView na may pare-parehong taas?

Itakda ang tableView.rowHeight = 80 at tableView.estimatedRowHeight = 0 o alisin ang estimatedRowHeight. Sa nakapirming taas, hindi tinatawag ng UITableView ang heightForRowAt, na nagpapabilis ng pag-render ng 5–10 beses para sa mga listahan na may 100+ elemento. Para sa mga cell na may custom na taas (iba't ibang nilalaman), gumamit ng self-sizing: estimatedRowHeight + UITableView.automaticDimension.

Buod

  • UITableView — pangunahing bahagi ng UIKit para sa mga vertical na listahan na may arkitekturang DataSource at Delegate.
  • UITableViewCell — 4 na built-in na estilo (.default, .subtitle, .value1, .value2) at custom sa pamamagitan ng contentConfiguration.
  • Reuse queue — pool ng mga reusable na cell; register + dequeueReusableCell + prepareForReuse sapilitan.
  • DiffableDataSource (iOS 13+) — type-safe na DataSource na may awtomatikong pagkalkula ng pagbabago at animation.
  • Pagganap: nakapirming rowHeight, prefetching, mas kaunting subview, mabibigat na operasyon sa background.
  • 85% ng iOS top-100 App Store app ay gumagamit ng UITableView para sa pagpapakita ng nilalaman.
  • Para sa mga grid, carousel, at kumplikadong layout, gamitin ang UICollectionView sa halip na UITableView.

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din