UITableView — a UIKit fő komponense függőleges listák megjelenítéséhez iOS-ben. A táblázat minden sora egy UITableViewCell cella előre meghatározott stílusokkal. Elmagyarázzuk a UITableView alapjait: DataSource, delegált, cellák újrafelhasználása és táblázatok teljesítménye iOS alkalmazásokban. Az Apple szerint (Human Interface Guidelines, 2026) a UITableView a legtöbbet használt UI komponens iOS-ben — az App Store top-100 alkalmazásának 85%-a tartalmaz legalább egy táblázatot. Komplex elrendezésekhez olvassa el a UICollectionView-ról szóló cikket.
Főbb pontok
UITableView — egy osztály a UIKit keretrendszerből, amely görgethető sorlista megjelenítésére szolgál egy oszlopban. Minden sort egy UITableViewCell objektum képvisel. Az UITableView az iPhone OS 2-ben (2008) jelent meg, és azóta is a listák fő komponense iOS-ben. Az UITableView architektúrája az MVC mintára épül: az adatokat a DataSource, a megjelenést és viselkedést a Delegate, a nézetet pedig maga a táblázat kezeli.
Két táblázatstílus: .plain (folyamatos lista opcionális szakaszokkal) és .grouped (csoportosított szakaszok lekerekített sarkokkal és margókkal). iOS 13 óta hozzáadták a .insetGrouped-et — grouped-stílus margókkal a szélektől, amelyet a Beállítások és Egészség alkalmazások használnak. A stílusválasztás befolyásolja az alapértelmezett megjelenést: a plain-táblázatok görgetéskor a szakasz fejlécét a tetejére rögzítik (sticky header), a grouped — nem.
iOS 8 óta az UITableView támogatja az automatikus méretű cellákat (self-sizing cells). Az aktiváláshoz állítsa be a tableView.estimatedRowHeight (pl. 80) és a tableView.rowHeight = UITableView.automaticDimension értékeket. A táblázat automatikusan kiszámítja a sor magasságát a cellán belüli Auto Layout korlátozások alapján. A self-sizing csökkenti a teljesítményt összetett cellák esetén — használjon rögzített magasságot (rowHeight) az 500+ elemű táblázatokhoz.
UITableViewCell négy beépített stílust kínál, amelyek az esetek 80%-át lefedik anélkül, hogy egyedi cellát kellene létrehozni. Minden stílus a textLabel, detailTextLabel és imageView kombinációjából áll. A stílusválasztás a cella inicializálásakor történik az init(style:reuseIdentifier:) segítségével.
| Stílus | textLabel | detailTextLabel | imageView | Példa |
|---|---|---|---|---|
| .default (.basic) | Balra, félkövér | Nincs | Opcionális | Menü, elemek listája |
| .subtitle | Balra, félkövér | A textLabel alatt, szürke | Opcionális | Névjegyek, lejátszási listák |
| .value1 | Balra, félkövér | Jobbra, szürke | Nincs | Beállítások értékekkel |
| .value2 | Jobbra, kék | Balra, szürke | Nincs | Telefonkönyv (iOS 6 stílus) |
// Táblázat létrehozása egyedi cellákkal
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+) — modern módja a cellák konfigurálásának a contentConfiguration segítségével a textLabel/detailTextLabel közvetlen elérése helyett. Használja a cell.defaultContentConfiguration() metódust, vagy hozzon létre egyedi UIContentConfiguration-t. Előnyök: dinamikus típus, sötét téma és VoiceOver támogatás a dobozból. Az Apple (WWDC 2024) a contentConfiguration-t ajánlja minden új UITableView-hez.
UITableViewDataSource — protokoll, amely adatokat biztosít a táblázat számára. Kötelező metódusok: tableView(_:numberOfRowsInSection:) és tableView(_:cellForRowAt:). Nélkülük a táblázat nem tud egyetlen sort sem megjeleníteni. UITableViewDelegate — protokoll a megjelenés és viselkedés kezelésére: sormagasság, kijelölés, szerkesztés, contextual actions.
// Példa több szakasszal és szerkesztéssel
extension ContactListController: UITableViewDelegate {
// Egyedi magasság minden sorhoz
func tableView(_ tableView: UITableView,
heightForRowAt indexPath: IndexPath) -> CGFloat {
80
}
// Kijelölés kezelése
func tableView(_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let contact = contacts[indexPath.row]
showDetail(for: contact)
}
// Csúsztatás a törléshez
func tableView(_ tableView: UITableView,
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath)
-> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .destructive, title: "Törlés") {
[weak self] _, _, completion in
self?.contacts.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
completion(true)
}
return UISwipeActionsConfiguration(actions: [deleteAction])
}
}
Delegate teljesítmény: a méretmetódusok (heightForRowAt) minden látható sorra meghívódnak minden görgetéskor. Egységes magassághoz állítsa be közvetlenül a rowHeight-ot — ez 10-szer gyorsabb, mint a heightForRowAt. A self-sizing cellákhoz állítsa be az estimatedRowHeight és automaticDimension értékeket — a táblázat csak a látható sorokhoz hívja meg a heightForRowAt-ot, a többihez az estimatedRowHeight-t használja.
Reuse queue — újrafelhasználható UITableView cellák készlete. Amikor egy cella elhagyja a képernyőt, nem törlődik, hanem a sorba kerül. Új cellák nem a semmiből jönnek létre — a rendszer meghívja a dequeueReusableCell(withIdentifier:for:) metódust, amely visszaad egy cellát a sorból, vagy újat hoz létre, ha a sor üres. Ez az UITableView teljesítményének kulcsmechanizmusa.
// Egyedi cella gyorsítótárazással
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)
// Auto Layout korlátozások beállítása
avatarView.translatesAutoresizingMaskIntoConstraints = false
// ... korlátozások ...
}
func configure(with contact: Contact) {
nameLabel.text = contact.name
subtitleLabel.text = contact.phone
// Avatár aszinkron betöltése
}
override func prepareForReuse() {
super.prepareForReuse()
avatarView.image = nil
nameLabel.text = nil
subtitleLabel.text = nil
}
}
// Regisztráció és használat
tableView.register(ContactCell.self, forCellReuseIdentifier: "contactCell")
// A cellForRowAt-ban:
let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactCell
cell.configure(with: contacts[indexPath.row])
return cell
prepareForReuse() — metódus, amelyet a cella reuse queue-ba helyezése előtt hívnak meg. Állítsa vissza a cella teljes állapotát: szöveg, képek, animációk, betöltések. A prepareForReuse nélkül egy újrahasznált cella régi adatokat jeleníthet meg: az előző kép egy pillanatra látható lesz, amíg az új be nem töltődik. Az Apple (WWDC 2023) az aszinkron műveletek törlését javasolja a URLSessionTask.cancel() segítségével a prepareForReuse-ben.
Szakaszok az UITableView-ben logikailag kapcsolódó sorokat csoportosítanak. Minden szakasznak lehet header (fejléc) és footer (lábléc). A szakaszok számát a numberOfSections(in:) metódus határozza meg (alapértelmezett 1). A grouped és insetGrouped stílusoknál a szakaszok vizuálisan el vannak választva margókkal és lekerekített sarkokkal.
| DataSource metódus | Leírás | Visszatérési érték |
|---|---|---|
| numberOfSections | Szakaszok száma (alapértelmezett 1) | Int |
| numberOfRowsInSection | Sorok száma a szakaszban | Int |
| titleForHeaderInSection | Szakasz fejlécének szövege | String? |
| titleForFooterInSection | Szakasz láblécének szövege | String? |
| viewForHeaderInSection | Egyedi nézet a header-hez | UIView? |
| heightForHeaderInSection | Header magassága | CGFloat |
Indexelés: a szakaszok közötti gyors navigációhoz adjon hozzá egy indexet — egy karakterlánc-tömböt, amely a jobb oldalon jelenik meg. Implementálja a sectionIndexTitles(for:) metódust — visszaadja az egyes szakaszok első betűinek tömbjét. 26+ szakasz esetén ez kritikusan javítja az UX-et. iOS 15+-ben a táblázatok támogatják a sectionHeaderTopPadding-et — a státuszsor és az első header közötti távolság, amely 0-ra állítható a kompakt elrendezéshez.
Teljesítmény Az UITableView kritikus fontosságú a hosszú listákat tartalmazó alkalmazások számára. Fő problémák: lassú görgetés (jank) a nehéz műveletek miatt a cellForRowAt-ban, a heightForRowAt gyakori meghívása, a prefetching hiánya. Az Apple (WWDC 2025) öt kulcsfontosságú gyakorlatot emel ki az 1000+ elemű táblázatokhoz.
// Optimalizálás prefetchinggel
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)
}
}
}
// DiffableDataSource használata zökkenőmentes frissítésekhez
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)
}
}
Gyakorlati eredmény: ezen optimalizálások alkalmazása 30-ról 60-ra növeli a görgetési FPS-t iPhone 12 és régebbi eszközökön (az Apple tesztek szerint, 2025). Az IT Sectr projektekben a DiffableDataSource-t használjuk minden új táblázathoz, és prefetching-et adunk a képeket tartalmazó táblázatokhoz (avatárok, előnézetek, alkalmazásikonok).
Gyakran ismételt kérdések
Ellenőrizze: (1) contentSize > frame.size — a táblázatnak több tartalommal kell rendelkeznie, mint a magassága; (2) a táblázat nincs egy másik UIScrollView-n belül, amely elfogja a gesztusokat; (3) isScrollEnabled = true; (4) a numberOfRowsInSection a megfelelő számot adja vissza. Tipikus probléma — egy táblázat heightForRowAt = UITableView.automaticDimension értékkel estimatedRowHeight nélkül, ami végtelen magasságszámításhoz vezet.
Használja a performBatchUpdates vagy a DiffableDataSource metódust a reloadData() helyett. A reloadData() teljes újratöltést okoz animáció nélkül, vizuális villogást létrehozva. Pontszerű frissítéshez használja: reloadRows(at:with:), insertRows, deleteRows. A performBatchUpdates-en belüli összes változás egyszerre animálódik. A DiffableDataSource ezt automatikusan teszi kézi hívások nélkül.
UITableView — egyoszlopos függőleges lista előre meghatározott cellastílusokkal és beépített szerkesztéssel. UICollectionView — rugalmas elrendezés (rács, lista, körhinta, kaszkád) az elemek tetszőleges elhelyezésével. Válassza az UITableView-t egyszerű listákhoz (beállítások, névjegyek, üzenetek). Válassza az UICollectionView-t galériákhoz, katalógusokhoz, táblákhoz és bármilyen nem lineáris elrendezéshez.
Állítsa be a tableView.tableFooterView = UIView(frame: .zero) értéket. Alapértelmezés szerint az UITableView üres sorokat (elválasztókat) jelenít meg az utolsó elem alatt az alsó széléig. Egy üres UIView beállítása a tableFooterView-ban eltávolítja őket. A grouped-stílushoz ez nem szükséges — a táblázat csak a tényleges sorokat jeleníti meg az utolsó szakasz lekerekített sarkaival.
Állítsa be a tableView.rowHeight = 80 és a tableView.estimatedRowHeight = 0 értékeket, vagy hagyja ki az estimatedRowHeight-t. Rögzített magassággal az UITableView nem hívja meg a heightForRowAt-ot, ami 5–10-szeresére gyorsítja a renderelést a 100+ elemű listáknál. Egyedi magasságú cellákhoz (eltérő tartalom) használjon self-sizing-et: estimatedRowHeight + UITableView.automaticDimension.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is