UITableView: Grundlagen, Listen und Zellen in iOS-Apps

Autor: IT Sectr Veröffentlicht: 2026-02-23 Lesezeit: 9 Min.

UITableView — die Hauptkomponente von UIKit zur Anzeige vertikaler Listen in iOS. Jede Tabellenzeile ist eine UITableViewCell mit vordefinierten Stilen. Wir erklären die Grundlagen von UITableView: DataSource, Delegat, Wiederverwendung von Zellen und Tabellenleistung in iOS-Anwendungen. Laut Apple (Human Interface Guidelines, 2026) bleibt UITableView die am häufigsten verwendete UI-Komponente in iOS — 85% der Apps in den Top 100 des App Store enthalten mindestens eine Tabelle. Für komplexe Layouts lesen Sie den Artikel über UICollectionView.

Wichtige Punkte

  • UITableView — eine UIKit-Komponente für vertikale Listen, verfügbar seit iOS 2.0 (iPhone OS 2).
  • UITableViewCell — eine Tabellenzelle mit vier integrierten Stilen und Anpassungsmöglichkeiten.
  • UITableViewDataSource — ein Protokoll, das die Anzahl der Zeilen und Zellen für jeden Abschnitt definiert.
  • UITableViewDelegate — ein Protokoll zur Behandlung von Auswahl, Bearbeitung und Zeilenhöhenkonfiguration.
  • UITableViewDiffableDataSource — eine moderne DataSource (iOS 13+) mit automatischer Änderungsberechnung.

Was ist UITableView in iOS?

UITableView ist eine Klasse aus dem UIKit-Framework, die zur Anzeige einer scrollbaren Liste von Zeilen in einer einzigen Spalte entwickelt wurde. Jede Zeile wird durch ein UITableViewCell-Objekt dargestellt. UITableView erschien erstmals in iPhone OS 2 (2008) und ist seitdem die Hauptkomponente für Listen in iOS. Die Architektur von UITableView basiert auf dem MVC-Muster: Daten werden von der DataSource verwaltet, Aussehen und Verhalten vom Delegate und die Darstellung von der Tabelle selbst.

Zwei Tabellenstile: .plain (durchgehende Liste mit optionalen Abschnitten) und .grouped (gruppierte Abschnitte mit abgerundeten Ecken und Rändern). iOS 13 fügte .insetGrouped hinzu — einen gruppierten Stil mit Randabständen, der in den Apps Einstellungen und Gesundheit verwendet wird. Die Wahl des Stils beeinflusst das Standard-Erscheinungsbild: Plain-Tabellen fixieren Abschnittsüberschriften beim Scrollen oben (sticky header), grouped-Tabellen nicht.

Self-Sizing Cells

Ab iOS 8 unterstützt UITableView selbstanpassende Zellen (self-sizing cells). Zum Aktivieren setzen Sie tableView.estimatedRowHeight (z. B. 80) und tableView.rowHeight = UITableView.automaticDimension. Die Tabelle berechnet die Zeilenhöhe automatisch basierend auf den Auto-Layout-Beschränkungen innerhalb der Zelle. Self-Sizing reduziert die Leistung bei komplexen Zellen — verwenden Sie eine feste Höhe (rowHeight) für Tabellen mit 500+ Elementen.

UITableViewCell-Stile: Basic, Subtitle, Value1, Value2

UITableViewCell bietet vier integrierte Stile, die 80% der Szenarien abdecken, ohne dass eine benutzerdefinierte Zelle erstellt werden muss. Jeder Stil besteht aus einer Kombination von textLabel, detailTextLabel und imageView. Der Stil wird beim Initialisieren der Zelle über init(style:reuseIdentifier:) ausgewählt.

StiltextLabeldetailTextLabelimageViewBeispiel
.default (.basic)Links, fettKeinerOptionalMenü, Liste von Elementen
.subtitleLinks, fettUnter textLabel, grauOptionalKontakte, Wiedergabelisten
.value1Links, fettRechts, grauKeinerEinstellungen mit Werten
.value2Rechts, blauLinks, grauKeinerTelefonbuch (iOS 6-Stil)
swift
// Erstellen einer Tabelle mit benutzerdefinierten Zellen
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+) — eine moderne Möglichkeit, Zellen über contentConfiguration zu konfigurieren, anstatt direkt auf textLabel/detailTextLabel zuzugreifen. Verwenden Sie cell.defaultContentConfiguration() oder erstellen Sie eine benutzerdefinierte UIContentConfiguration. Vorteile: integrierte Unterstützung für Dynamic Type, Dunkelmodus und VoiceOver. Apple (WWDC 2024) empfiehlt contentConfiguration für alle neuen UITableViews.

DataSource und Delegate: erforderliche Methoden

UITableViewDataSource — ein Protokoll, das Daten für die Tabelle bereitstellt. Erforderliche Methoden: tableView(_:numberOfRowsInSection:) und tableView(_:cellForRowAt:). Ohne sie kann die Tabelle keine einzige Zeile anzeigen. UITableViewDelegate — ein Protokoll zur Verwaltung von Aussehen und Verhalten: Zeilenhöhe, Auswahl, Bearbeitung, kontextbezogene Aktionen.

swift
// Beispiel mit mehreren Abschnitten und Bearbeitung
extension ContactListController: UITableViewDelegate {

    // Benutzerdefinierte Höhe für jede Zeile
    func tableView(_ tableView: UITableView,
                         heightForRowAt indexPath: IndexPath) -> CGFloat {
        80
    }

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

    // Swipe-to-delete
    func tableView(_ tableView: UITableView,
                         trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath)
        -> UISwipeActionsConfiguration? {
        let deleteAction = UIContextualAction(style: .destructive, title: "Löschen") {
            [weak self] _, _, completion in
            self?.contacts.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .automatic)
            completion(true)
        }
        return UISwipeActionsConfiguration(actions: [deleteAction])
    }
}

Delegate-Leistung: Größenmethoden (heightForRowAt) werden bei jedem Scrollen für jede sichtbare Zeile aufgerufen. Für eine gleichmäßige Höhe setzen Sie direkt rowHeight — das ist 10-mal schneller als heightForRowAt. Für selbstanpassende Zellen setzen Sie estimatedRowHeight und automaticDimension — die Tabelle ruft heightForRowAt nur für sichtbare Zeilen auf und verwendet estimatedRowHeight für die restlichen.

Zellenwiederverwendung: Wiederverwendungs-Warteschlange und Registrierung

Wiederverwendungs-Warteschlange — ein Pool wiederverwendbarer UITableView-Zellen. Wenn eine Zelle aus dem Bildschirm scrollt, wird sie nicht gelöscht, sondern in die Warteschlange gestellt. Neue Zellen werden nicht von Grund auf erstellt — das System ruft dequeueReusableCell(withIdentifier:for:) auf, das eine Zelle aus der Warteschlange zurückgibt oder eine neue erstellt, wenn die Warteschlange leer ist. Dies ist der wichtigste Leistungsmechanismus von UITableView.

swift
// Benutzerdefinierte Zelle mit 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)

        // Konfigurieren von Auto-Layout-Beschränkungen
        avatarView.translatesAutoresizingMaskIntoConstraints = false
        // ... constraints ...
    }

    func configure(with contact: Contact) {
        nameLabel.text = contact.name
        subtitleLabel.text = contact.phone
        // Asynchrones Laden von Avataren
    }

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

// Registrierung und Verwendung
tableView.register(ContactCell.self, forCellReuseIdentifier: "contactCell")

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

prepareForReuse() — eine Methode, die aufgerufen wird, bevor eine Zelle in die Wiederverwendungs-Warteschlange gestellt wird. Setzen Sie den gesamten Zellenzustand zurück: Text, Bilder, Animationen, Ladevorgänge. Ohne prepareForReuse kann eine wiederverwendete Zelle alte Daten anzeigen: Das vorherige Bild ist für einen Bruchteil einer Sekunde sichtbar, bis das neue geladen wird. Apple (WWDC 2023) empfiehlt, asynchrone Operationen über URLSessionTask.cancel() in prepareForReuse abzubrechen.

Abschnitte, Kopf- und Fußzeile: Daten gruppieren

Abschnitte in UITableView gruppieren logisch zusammengehörige Zeilen. Jeder Abschnitt kann eine Kopfzeile (header) und eine Fußzeile (footer) haben. Die Anzahl der Abschnitte wird durch die Methode numberOfSections(in:) bestimmt (Standard ist 1). Bei grouped- und insetGrouped-Stilen sind die Abschnitte visuell durch Ränder und abgerundete Ecken getrennt.

DataSource-MethodeBeschreibungRückgabewert
numberOfSectionsAnzahl der Abschnitte (Standard 1)Int
numberOfRowsInSectionAnzahl der Zeilen in einem AbschnittInt
titleForHeaderInSectionText der AbschnittsüberschriftString?
titleForFooterInSectionText der AbschnittsfußzeileString?
viewForHeaderInSectionBenutzerdefinierte Ansicht für KopfzeileUIView?
heightForHeaderInSectionHöhe der KopfzeileCGFloat

Indizierung: Für die schnelle Navigation zwischen Abschnitten fügen Sie einen Index-Titel hinzu — ein Array von Zeichenfolgen, die auf der rechten Seite angezeigt werden. Implementieren Sie sectionIndexTitles(for:) — gibt ein Array der ersten Buchstaben jedes Abschnitts zurück. Bei 26+ Abschnitten verbessert dies die UX erheblich. Unter iOS 15+ unterstützen Tabellen sectionHeaderTopPadding — den Abstand zwischen der Statusleiste und der ersten Kopfzeile, der für ein dichtes Layout auf 0 zurückgesetzt werden kann.

UITableView-Leistung: Best Practices

Die Leistung von UITableView ist für Apps mit langen Listen entscheidend. Häufige Probleme: langsames Scrollen (Jank) aufgrund schwerer Operationen in cellForRowAt, häufige heightForRowAt-Aufrufe, fehlendes Prefetching. Apple (WWDC 2025) hebt fünf wichtige Praktiken für Tabellen mit 1000+ Elementen hervor.

  • Einheitliche Höhe — verwenden Sie konstantes rowHeight anstelle von heightForRowAt für alle Zellen. Unterschied: 60 FPS vs. 30 FPS für eine Tabelle mit 500 Zeilen.
  • Prefetching — implementieren Sie UITableViewDataSourcePrefetching für asynchrones Datenladen (Bilder, API), bevor die Zelle auf dem Bildschirm erscheint.
  • Weniger Subviews — jede Subview in contentView erhöht die Renderzeit. Verwenden Sie draw() für einfache Grafiken (Trennlinien, Symbole) anstelle von UIImageView.
  • Schwere Operationen im Hintergrund — Datumsformatierung, Lokalisierung, Berechnungen sollten im Modell erfolgen, nicht in cellForRowAt. Verwenden Sie NSCache für Ergebnisse.
  • DiffableDataSource — ersetzen Sie reloadData() durch apply(snapshot) — die Animation erfolgt kostenlos, die Tabelle wird nicht vollständig neu geladen.
swift
// Optimierung mit 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)
        }
    }
}

// Verwendung von DiffableDataSource für flüssige Aktualisierungen
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)
    }
}

Praktisches Ergebnis: Die Anwendung dieser Optimierungen erhöht die Scroll-FPS von 30 auf 60 auf iPhone 12 und neueren Geräten (laut Apple-Testdaten, 2025). In IT Sectr-Projekten verwenden wir DiffableDataSource für alle neuen Tabellen und fügen Prefetching für Tabellen mit Bildern hinzu (Avatare, Vorschauen, App-Symbole).

Häufig gestellte Fragen

UITableView scrollt nicht — was tun?

Überprüfen Sie: (1) contentSize > frame.size — die Tabelle muss mehr Inhalt als ihre Höhe haben; (2) die Tabelle befindet sich nicht in einer anderen UIScrollView, die Gesten abfängt; (3) isScrollEnabled = true; (4) numberOfRowsInSection gibt die korrekte Anzahl zurück. Ein typisches Problem ist eine Tabelle mit heightForRowAt = UITableView.automaticDimension ohne estimatedRowHeight, was zu einer unendlichen Höhenberechnung führt.

Wie aktualisiere ich UITableView ohne Flackern?

Verwenden Sie performBatchUpdates oder DiffableDataSource anstelle von reloadData(). reloadData() verursacht ein vollständiges Neuladen ohne Animation, was visuelles Flackern erzeugt. Für gezielte Aktualisierungen verwenden Sie: reloadRows(at:with:), insertRows, deleteRows. Alle Änderungen innerhalb von performBatchUpdates werden gleichzeitig animiert. DiffableDataSource erledigt dies automatisch ohne manuelle Aufrufe.

Was ist der Unterschied zwischen UITableView und UICollectionView?

UITableView ist eine einspaltige vertikale Liste mit vordefinierten Zellstilen und integrierter Bearbeitung. UICollectionView ist ein flexibles Layout (Raster, Liste, Karussell, Wasserfall) mit beliebiger Elementpositionierung. Wählen Sie UITableView für einfache Listen (Einstellungen, Kontakte, Nachrichten). Wählen Sie UICollectionView für Galerien, Kataloge, Boards und alle nichtlinearen Layouts.

Wie entferne ich leere Zeilen unter dem Inhalt in UITableView?

Setzen Sie tableView.tableFooterView = UIView(frame: .zero). Standardmäßig zeigt UITableView leere Zeilen (Trennlinien) unterhalb des letzten Elements bis zum unteren Rand an. Das Setzen einer leeren UIView als tableFooterView entfernt sie. Für den grouped-Stil ist dies nicht erforderlich — die Tabelle zeigt nur die tatsächlichen Zeilen mit abgerundeten Ecken im letzten Abschnitt an.

Wie erstelle ich eine UITableView mit konstanter Höhe?

Setzen Sie tableView.rowHeight = 80 und tableView.estimatedRowHeight = 0 oder lassen Sie estimatedRowHeight weg. Bei fester Höhe ruft UITableView heightForRowAt nicht auf, was das Rendern für Listen mit 100+ Elementen um das 5- bis 10-fache beschleunigt. Für Zellen mit benutzerdefinierter Höhe (unterschiedlicher Inhalt) verwenden Sie Self-Sizing: estimatedRowHeight + UITableView.automaticDimension.

Zusammenfassung

  • UITableView — die Haupt-UIKit-Komponente für vertikale Listen mit DataSource- und Delegate-Architektur.
  • UITableViewCell — 4 integrierte Stile (.default, .subtitle, .value1, .value2) und benutzerdefinierte über contentConfiguration.
  • Wiederverwendungs-Warteschlange — ein Pool wiederverwendbarer Zellen; register + dequeueReusableCell + prepareForReuse sind obligatorisch.
  • DiffableDataSource (iOS 13+) — eine typsichere DataSource mit automatischer Änderungsberechnung und Animation.
  • Leistung: feste rowHeight, Prefetching, weniger Subviews, schwere Operationen im Hintergrund.
  • 85% der iOS-Apps in den Top 100 des App Store verwenden UITableView zur Anzeige von Inhalten.
  • Für Raster, Karussells und komplexe Layouts verwenden Sie UICollectionView anstelle von UITableView.

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch