UITableView: əsaslar, iOS tətbiqlərində siyahılar və hüceyrələr

Müəllif: IT Sectr Dərc olunub: 2026-02-23 Oxuma vaxtı: 9 dəq

UITableView — iOS-da şaquli siyahıları göstərmək üçün UIKit-in əsas komponentidir. Cədvəlin hər sətri əvvəlcədən təyin edilmiş stilləri olan UITableViewCell hüceyrəsidir. UITableView-in əsaslarını izah edirik: DataSource, delegate, hüceyrələrin təkrar istifadəsi və iOS tətbiqlərində cədvəllərin performansı. Apple-ın məlumatına görə (Human Interface Guidelines, 2026), UITableView iOS-da ən çox istifadə edilən UI komponenti olaraq qalır — App Store top-100 tətbiqinin 85%-i ən azı bir cədvəl ehtiva edir. Mürəkkəb maketlər üçün UICollectionView haqqında məqaləni oxuyun.

Əsas məqamlar

  • UITableView — şaquli siyahılar üçün UIKit komponenti, iOS 2.0-dan (iPhone OS 2) mövcuddur.
  • UITableViewCell — dörd daxili stili və fərdiləşdirmə imkanı olan cədvəl hüceyrəsi.
  • UITableViewDataSource — hər bölmə üçün sətir və hüceyrə sayını təyin edən protokol.
  • UITableViewDelegate — seçim, redaktə və sətir hündürlüyünün tənzimlənməsi üçün protokol.
  • UITableViewDiffableDataSource — dəyişikliklərin avtomatik hesablanması ilə müasir DataSource (iOS 13+).

iOS-da UITableView nədir?

UITableView — bir sütunda sürüşdürülə bilən sətir siyahısını göstərmək üçün UIKit freymvorkundan olan sinifdir. Hər sətir UITableViewCell obyekti ilə təmsil olunur. UITableView iPhone OS 2-də (2008) meydana çıxdı və o vaxtdan iOS-da siyahılar üçün əsas komponent olaraq qalır. UITableView-in arxitekturası MVC nümunəsi üzərində qurulub: məlumatlar DataSource tərəfindən, görünüş və davranış Delegate tərəfindən, görünüş isə cədvəlin özü tərəfindən idarə olunur.

İki cədvəl stili: .plain (isteğe bağlı bölmələri olan fasiləsiz siyahı) və .grouped (yuvarlaq küncləri və boşluqları olan qruplaşdırılmış bölmələr). iOS 13-dən etibarən .insetGrouped əlavə edildi — kənarlardan boşluqları olan grouped-stil, Parametrlər və Sağlamlıq tətbiqlərində istifadə olunur. Stil seçimi standart görünüşə təsir edir: plain-cədvəllər sürüşdürmə zamanı bölmə headerini yuxarıya yapışdırır (sticky header), grouped — yapışdırmır.

Self-Sizing Cells

iOS 8-dən etibarən UITableView avtomatik ölçülü hüceyrələri (self-sizing cells) dəstəkləyir. Aktivləşdirmək üçün tableView.estimatedRowHeight (məsələn, 80) və tableView.rowHeight = UITableView.automaticDimension təyin edin. Cədvəl hüceyrə daxilindəki Auto Layout məhdudiyyətlərinə əsasən sətir hündürlüyünü avtomatik hesablayır. Self-sizing mürəkkəb hüceyrələr üçün performansı azaldır — 500+ elementi olan cədvəllər üçün sabit hündürlükdən (rowHeight) istifadə edin.

UITableViewCell stilləri: basic, subtitle, value1, value2

UITableViewCell xüsusi hüceyrə yaratmadan 80% ssenariləri əhatə edən dörd daxili stil təqdim edir. Hər stil textLabel, detailTextLabel və imageView kombinasiyasından ibarətdir. Stil seçimi hüceyrə işə salınarkən init(style:reuseIdentifier:) vasitəsilə təyin edilir.

StiltextLabeldetailTextLabelimageViewNümunə
.default (.basic)Sol, qalınYoxİsteğe bağlıMenu, element siyahısı
.subtitleSol, qalıntextLabel altında, bozİsteğe bağlıKontaktlar, pleylistlər
.value1Sol, qalınSağ, bozYoxDəyərləri olan parametrlər
.value2Sağ, maviSol, bozYoxTelefon kitabçası (iOS 6 stili)
swift
// Xüsusi hüceyrələrlə cədvəl yaratma
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+) — textLabel/detailTextLabel-ə birbaşa müraciət əvəzinə contentConfiguration vasitəsilə hüceyrələrin konfiqurasiyasının müasir üsulu. cell.defaultContentConfiguration() istifadə edin və ya xüsusi UIContentConfiguration yaradın. Üstünlükləri: dinamik tip, qaranlıq tema və VoiceOver dəstəyi qutudan çıxan kimi. Apple (WWDC 2024) bütün yeni UITableView-lər üçün contentConfiguration tövsiyə edir.

DataSource və Delegate: məcburi metodlar

UITableViewDataSource — cədvəl üçün məlumat təmin edən protokol. Məcburi metodlar: tableView(_:numberOfRowsInSection:)tableView(_:cellForRowAt:). Onlar olmadan cədvəl heç bir sətir göstərə bilməz. UITableViewDelegate — görünüş və davranışı idarə etmək üçün protokol: sətir hündürlüyü, seçim, redaktə, contextual actions.

swift
// Bir neçə bölmə və redaktə ilə nümunə
extension ContactListController: UITableViewDelegate {

    // Hər sətir üçün xüsusi hündürlük
    func tableView(_ tableView: UITableView,
                         heightForRowAt indexPath: IndexPath) -> CGFloat {
        80
    }

    // Seçimin işlənməsi
    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: "Sil") {
            [weak self] _, _, completion in
            self?.contacts.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .automatic)
            completion(true)
        }
        return UISwipeActionsConfiguration(actions: [deleteAction])
    }
}

Delegate performansı: ölçü metodları (heightForRowAt) hər sürüşdürmədə hər görünən sətir üçün çağırılır. Bərabər hündürlük üçün birbaşa rowHeight təyin edin — bu heightForRowAt-dan 10 dəfə sürətlidir. Self-sizing hüceyrələri üçün estimatedRowHeight və automaticDimension təyin edin — cədvəl heightForRowAt-ı yalnız görünən sətirlər üçün çağıracaq, qalanları üçün estimatedRowHeight istifadə edəcək.

Hüceyrələrin təkrar istifadəsi: reuse queue və register

Reuse queue — təkrar istifadə olunan UITableView hüceyrələrinin hovuzu. Hüceyrə ekranı tərk etdikdə silinmir, növbəyə qoyulur. Yeni hüceyrələr sıfırdan yaradılmır — sistem dequeueReusableCell(withIdentifier:for:) çağırır, bu da növbədən hüceyrə qaytarır və ya növbə boşdursa yenisini yaradır. Bu, UITableView performansının əsas mexanizmidir.

swift
// Keşləmə ilə xüsusi hüceyrə
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 məhdudiyyətlərinin qurulması
        avatarView.translatesAutoresizingMaskIntoConstraints = false
        // ... məhdudiyyətlər ...
    }

    func configure(with contact: Contact) {
        nameLabel.text = contact.name
        subtitleLabel.text = contact.phone
        // Avatarın asinxron yüklənməsi
    }

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

// Qeydiyyat və istifadə
tableView.register(ContactCell.self, forCellReuseIdentifier: "contactCell")

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

prepareForReuse() — hüceyrə reuse queue-ya qoyulmazdan əvvəl çağırılan metod. Hüceyrənin bütün vəziyyətini sıfırlayın: mətn, şəkillər, animasiyalar, yükləmələr. prepareForReuse olmadan təkrar istifadə edilən hüceyrə köhnə məlumatları göstərə bilər: əvvəlki şəkil yenisi yüklənənə qədər saniyənin bir hissəsi görünəcək. Apple (WWDC 2023) prepareForReuse-də URLSessionTask.cancel() vasitəsilə asinxron əməliyyatların təmizlənməsini tövsiyə edir.

Bölmələr, header və footer: məlumatların qruplaşdırılması

Bölmələr UITableView-də məntiqi əlaqəli sətirləri qruplaşdırır. Hər bölmənin header (başlıq) və footer (altlıq) ola bilər. Bölmələrin sayı numberOfSections(in:) metodu ilə müəyyən edilir (standart 1). Grouped və insetGrouped stilləri üçün bölmələr vizual olaraq boşluqlar və yuvarlaq künclərlə ayrılır.

DataSource metoduTəsvirQaytarılan dəyər
numberOfSectionsBölmələrin sayı (standart 1)Int
numberOfRowsInSectionBölmədəki sətirlərin sayıInt
titleForHeaderInSectionBölmə başlığının mətniString?
titleForFooterInSectionBölmə altlığının mətniString?
viewForHeaderInSectionHeader üçün xüsusi görünüşUIView?
heightForHeaderInSectionHeader hündürlüyüCGFloat

İndeksasiya: bölmələr üzrə sürətli naviqasiya üçün indeks əlavə edin — sağda göstərilən sətirlər massivi. sectionIndexTitles(for:) tətbiq edin — hər bölmənin ilk hərflərindən ibarət massiv qaytarır. 26+ bölmə üçün bu, UX-i ciddi şəkildə yaxşılaşdırır. iOS 15+-də cədvəllər sectionHeaderTopPadding dəstəkləyir — status barı ilə ilk header arasında sıx maket üçün 0-a endirilə bilən boşluq.

UITableView performansı: ən yaxşı təcrübələr

Performans UITableView uzun siyahıları olan tətbiqlər üçün kritik əhəmiyyət daşıyır. Əsas problemlər: cellForRowAt-da ağır əməliyyatlar səbəbindən yavaş sürüşdürmə (jank), heightForRowAt-ın tez-tez çağırılması, prefetching-in olmaması. Apple (WWDC 2025) 1000+ elementi olan cədvəllər üçün beş əsas təcrübəni vurğulayır.

  • Flat-height — bütün hüceyrələr üçün heightForRowAt əvəzinə sabit rowHeight istifadə edin. Fərq: 500 sətirli cədvəl üçün 60 FPS vs 30 FPS.
  • Prefetching — hüceyrə ekranda görünməzdən əvvəl məlumatların (şəkillər, API) asinxron yüklənməsi üçün UITableViewDataSourcePrefetching tətbiq edin.
  • Daha az subview — contentView-dəki hər subview render vaxtını artırır. UIImageView əvəzinə sadə qrafika (ayırıcılar, ikonlar) üçün draw() istifadə edin.
  • Ağır əməliyyatları fon edin — tarix formatlama, lokallaşdırma, hesablamaları modeldə yerinə yetirin, cellForRowAt-da yox. Nəticələr üçün NSCache istifadə edin.
  • DiffableDataSource — reloadData() əvəzinə apply(snapshot) istifadə edin — animasiya pulsuz baş verir, cədvəl tamamilə yenidən yüklənmir.
swift
// Prefetching ilə optimallaşdırma
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)
        }
    }
}

// Hamarlı yeniləmələr üçün DiffableDataSource istifadəsi
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)
    }
}

Praktiki nəticə: bu optimallaşdırmaların tətbiqi iPhone 12 və daha köhnə cihazlarda sürüşdürmə FPS-ni 30-dan 60-a qaldırır (Apple testlərinə görə, 2025). IT Sectr layihələrində bütün yeni cədvəllər üçün DiffableDataSource istifadə edirik və şəkilləri olan cədvəllərə (avatar, önbaxış, tətbiq ikonları) prefetching əlavə edirik.

Tez-tez verilən suallar

UITableView sürüşmür — nə etməli?

Yoxlayın: (1) contentSize > frame.size — cədvəlin məzmunu hündürlüyündən çox olmalıdır; (2) cədvəl jestləri ələ keçirən başqa UIScrollView-in içərisində deyil; (3) isScrollEnabled = true; (4) numberOfRowsInSection düzgün say qaytarır. Tipik problem — estimatedRowHeight olmadan heightForRowAt = UITableView.automaticDimension, bu da sonsuz hündürlük hesablamasına səbəb olur.

UITableView-i yanıb-sönmədən necə yeniləmək olar?

performBatchUpdates və ya DiffableDataSource istifadə edin reloadData() əvəzinə. reloadData() animasiyasız tam yenidən yükləməyə səbəb olur, vizual yanıb-sönmə yaradır. Nöqtəvi yeniləmə üçün istifadə edin: reloadRows(at:with:), insertRows, deleteRows. performBatchUpdates daxilindəki bütün dəyişikliklər eyni anda animasiya olunur. DiffableDataSource bunu əl çağırışları olmadan avtomatik edir.

UITableView və UICollectionView arasında nə fərq var?

UITableView — əvvəlcədən təyin edilmiş hüceyrə stilləri və daxili redaktə ilə tək sütunlu şaquli siyahı. UICollectionView — elementlərin ixtiyari yerləşdirilməsi ilə çevik maket (grid, siyahı, karusel, kaskad). Sadə siyahılar üçün UITableView seçin (parametrlər, kontaktlar, mesajlar). Qalereyalar, kataloqlar, lövhələr və istənilən qeyri-xətti maketlər üçün UICollectionView seçin.

UITableView-də məzmunun altındakı boş sətirləri necə silmək olar?

tableView.tableFooterView = UIView(frame: .zero) təyin edin. Standart olaraq UITableView son elementdən aşağı kənara qədər boş sətirləri (ayırıcıları) göstərir. tableFooterView-də boş UIView təyin etmək onları silir. Grouped-stil üçün bu tələb olunmur — cədvəl yalnız son bölmənin yuvarlaq küncləri ilə faktiki sətirləri göstərir.

Sabit hündürlüklü UITableView necə etmək olar?

tableView.rowHeight = 80tableView.estimatedRowHeight = 0 təyin edin və ya estimatedRowHeight-i buraxın. Sabit hündürlüklə UITableView heightForRowAt çağırmır, bu da 100+ elementi olan siyahılar üçün renderi 5–10 dəfə sürətləndirir. Xüsusi hündürlüklü hüceyrələr (müxtəlif məzmun) üçün self-sizing istifadə edin: estimatedRowHeight + UITableView.automaticDimension.

Nəticə

  • UITableView — DataSource və Delegate arxitekturası ilə şaquli siyahılar üçün əsas UIKit komponenti.
  • UITableViewCell — 4 daxili stil (.default, .subtitle, .value1, .value2) və contentConfiguration vasitəsilə xüsusi hüceyrələr.
  • Reuse queue — təkrar istifadə olunan hüceyrələr hovuzu; register + dequeueReusableCell + prepareForReuse məcburidir.
  • DiffableDataSource (iOS 13+) — avtomatik dəyişiklik hesablanması və animasiya ilə tip-təhlükəsiz DataSource.
  • Performans: sabit rowHeight, prefetching, daha az subview, ağır əməliyyatlar fonda.
  • App Store top-100 iOS tətbiqinin 85%-i məzmun göstərmək üçün UITableView istifadə edir.
  • Gridlər, karusellər və mürəkkəb maketlər üçün UITableView əvəzinə UICollectionView istifadə edin.

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun