UITableView — iOS da vertikal ro'yxatlarni ko'rsatish uchun UIKit ning asosiy komponenti. Jadvalning har bir qatori oldindan belgilangan uslubdagi UITableViewCell hujayrasidir. UITableView asoslarini tushuntiramiz: DataSource, delegat, hujayralarni qayta ishlatish va iOS ilovalarida jadvallar ishlashi. Apple ma'lumotlariga ko'ra (Human Interface Guidelines, 2026), UITableView iOS da eng ko'p ishlatiladigan UI komponent bo'lib qolmoqda — App Store top-100 ilovalarining 85% kamida bitta jadvalni o'z ichiga oladi. Murakkab maketlar uchun UICollectionView haqidagi maqolani o'qing.
Asosiy fikrlar
UITableView — bir ustunda aylantiriladigan qatorlar ro'yxatini ko'rsatish uchun UIKit frameworkidagi sinf. Har bir qator UITableViewCell obyekti bilan ifodalanadi. UITableView iPhone OS 2 (2008) da paydo bo'lgan va shu vaqtdan beri iOS da ro'yxatlar uchun asosiy komponent bo'lib qolmoqda. UITableView arxitekturasi MVC naqshiga asoslangan: ma'lumotlar DataSource tomonidan, ko'rinish va xatti-harakat Delegate tomonidan, ko'rinish esa jadvalning o'zi tomonidan boshqariladi.
Ikki jadval uslubi: .plain (ixtiyoriy bo'limlar bilan uzluksiz ro'yxat) va .grouped.insetGrouped qo'shilgan — chekkalardan bo'shliqlar bilan grouped-uslub, Sozlamalar va Salomatlik ilovalarida ishlatiladi. Uslub tanlovi standart ko'rinishga ta'sir qiladi: plain-jadvallar aylantirishda bo'lim headerini yuqoriga yopishtiradi (sticky header), grouped — yopishtirmaydi.
iOS 8 dan boshlab, UITableView avtomatik o'lchamli hujayralarni (self-sizing cells) qo'llab-quvvatlaydi. Faollashtirish uchun tableView.estimatedRowHeight (masalan, 80) va tableView.rowHeight = UITableView.automaticDimension ni o'rnating. Jadval hujayra ichidagi Auto Layout cheklovlari asosida qator balandligini avtomatik hisoblaydi. Self-sizing murakkab hujayralar uchun ishlashni pasaytiradi — 500+ elementli jadvallar uchun doimiy balandlikdan (rowHeight) foydalaning.
UITableViewCell maxsus hujayra yaratmasdan 80% stsenariylarni qamrab oladigan to'rtta o'rnatilgan uslubni taqdim etadi. Har bir uslub textLabel, detailTextLabel va imageView kombinatsiyasidan iborat. Uslub tanlovi hujayra ishga tushirilganda init(style:reuseIdentifier:) orqali o'rnatiladi.
| Uslub | textLabel | detailTextLabel | imageView | Misol |
|---|---|---|---|---|
| .default (.basic) | Chap, qalin | Yo'q | Ixtiyoriy | Menyu, elementlar ro'yxati |
| .subtitle | Chap, qalin | textLabel ostida, kulrang | Ixtiyoriy | Kontaktlar, pleylistlar |
| .value1 | Chap, qalin | O'ng, kulrang | Yo'q | Qiymatlar bilan sozlamalar |
| .value2 | O'ng, ko'k | Chap, kulrang | Yo'q | Telefon daftarchasi (iOS 6 uslubi) |
// Maxsus hujayralar bilan jadval yaratish
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 ga to'g'ridan-to'g'ri murojaat qilish o'rniga contentConfiguration orqali hujayralarni sozlashning zamonaviy usuli. cell.defaultContentConfiguration() dan foydalaning yoki maxsus UIContentConfiguration yarating. Afzalliklari: dinamik tip, qorong'u mavzu va VoiceOver qutidan chiqishi bilan qo'llab-quvvatlanadi. Apple (WWDC 2024) barcha yangi UITableView lar uchun contentConfiguration ni tavsiya qiladi.
UITableViewDataSource — jadval uchun ma'lumotlarni ta'minlaydigan protokol. Majburiy metodlar: tableView(_:numberOfRowsInSection:) va tableView(_:cellForRowAt:). Ularsiz jadval hech qanday qatorni ko'rsata olmaydi. UITableViewDelegate — ko'rinish va xatti-harakatni boshqarish uchun protokol: qator balandligi, tanlash, tahrirlash, contextual actions.
// Bir nechta bo'lim va tahrirlash bilan misol
extension ContactListController: UITableViewDelegate {
// Har bir qator uchun maxsus balandlik
func tableView(_ tableView: UITableView,
heightForRowAt indexPath: IndexPath) -> CGFloat {
80
}
// Tanlashni qayta ishlash
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: "O'chirish") {
[weak self] _, _, completion in
self?.contacts.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
completion(true)
}
return UISwipeActionsConfiguration(actions: [deleteAction])
}
}
Delegate ishlashi: o'lcham metodlari (heightForRowAt) har bir aylantirishda har bir ko'rinadigan qator uchun chaqiriladi. Teng balandlik uchun to'g'ridan-to'g'ri rowHeight ni o'rnating — bu heightForRowAt dan 10 marta tezroq. Self-sizing hujayralari uchun estimatedRowHeight va automaticDimension ni o'rnating — jadval heightForRowAt ni faqat ko'rinadigan qatorlar uchun chaqiradi, qolganlari uchun estimatedRowHeight dan foydalanadi.
Reuse queue — qayta ishlatiladigan UITableView hujayralari havzasi. Hujayra ekranni tark etganda, o'chirilmaydi, balki navbatga qo'yiladi. Yangi hujayralar noldan yaratilmaydi — tizim dequeueReusableCell(withIdentifier:for:) ni chaqiradi, u navbatdan hujayra qaytaradi yoki navbat bo'sh bo'lsa yangisini yaratadi. Bu UITableView ishlashining asosiy mexanizmidir.
// Keshlash bilan maxsus hujayra
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 cheklovlarini sozlash
avatarView.translatesAutoresizingMaskIntoConstraints = false
// ... cheklovlar ...
}
func configure(with contact: Contact) {
nameLabel.text = contact.name
subtitleLabel.text = contact.phone
// Avatarni asinxron yuklash
}
override func prepareForReuse() {
super.prepareForReuse()
avatarView.image = nil
nameLabel.text = nil
subtitleLabel.text = nil
}
}
// Ro'yxatdan o'tkazish va foydalanish
tableView.register(ContactCell.self, forCellReuseIdentifier: "contactCell")
// cellForRowAt da:
let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactCell
cell.configure(with: contacts[indexPath.row])
return cell
prepareForReuse() — hujayra reuse queue ga qo'yilishidan oldin chaqiriladigan metod. Hujayraning barcha holatini tiklang: matn, tasvirlar, animatsiyalar, yuklamalar. prepareForReuse bo'lmasa, qayta ishlatilgan hujayra eski ma'lumotlarni ko'rsatishi mumkin: oldingi tasvir yangisi yuklanmaguncha soniyaning bir qismi ko'rinadi. Apple (WWDC 2023) prepareForReuse da URLSessionTask.cancel() orqali asinxron operatsiyalarni tozalashni tavsiya qiladi.
Bo'limlar UITableView da mantiqiy bog'langan qatorlarni guruhlaydi. Har bir bo'lim header (sarlavha) va footer (pastki) ga ega bo'lishi mumkin. Bo'limlar soni numberOfSections(in:) metodi bilan aniqlanadi (standart 1). Grouped va insetGrouped uslublari uchun bo'limlar vizual ravishda bo'shliqlar va yumaloq burchaklar bilan ajratiladi.
| DataSource metodi | Tavsif | Qaytariladigan qiymat |
|---|---|---|
| numberOfSections | Bo'limlar soni (standart 1) | Int |
| numberOfRowsInSection | Bo'limdagi qatorlar soni | Int |
| titleForHeaderInSection | Bo'lim sarlavhasi matni | String? |
| titleForFooterInSection | Bo'lim pastki matni | String? |
| viewForHeaderInSection | Header uchun maxsus ko'rinish | UIView? |
| heightForHeaderInSection | Header balandligi | CGFloat |
Indekslash: bo'limlar bo'ylab tez navigatsiya uchun indeks qo'shing — o'ng tomonda ko'rsatiladigan satrlar massivi. sectionIndexTitles(for:) ni amalga oshiring — har bir bo'limning birinchi harflaridan iborat massivni qaytaradi. 26+ bo'lim uchun bu UX ni keskin yaxshilaydi. iOS 15+ da jadvallar sectionHeaderTopPadding ni qo'llab-quvvatlaydi — status bar va birinchi header o'rtasidagi zich maket uchun 0 ga tushirilishi mumkin bo'lgan bo'shliq.
Ishlash UITableView uzoq ro'yxatli ilovalar uchun juda muhimdir. Asosiy muammolar: cellForRowAt dagi og'ir operatsiyalar tufayli sekin aylantirish (jank), heightForRowAt ning tez-tez chaqirilishi, prefetching ning yo'qligi. Apple (WWDC 2025) 1000+ elementli jadvallar uchun beshta asosiy amaliyotni ta'kidlaydi.
// Prefetching bilan optimallashtirish
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)
}
}
}
// Silliq yangilanishlar uchun DiffableDataSource dan foydalanish
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)
}
}
Amaliy natija: ushbu optimallashtirishlarni qo'llash iPhone 12 va undan eski qurilmalarda aylantirish FPS ni 30 dan 60 ga oshiradi (Apple testlariga ko'ra, 2025). IT Sectr loyihalarida barcha yangi jadvallar uchun DiffableDataSource dan foydalanamiz va tasvirlar (avatarlar, oldindan ko'rish, ilova belgilari) bo'lgan jadvallarga prefetching qo'shamiz.
Tez-tez beriladigan savollar
Tekshiring: (1) contentSize > frame.size — jadval balandligidan ko'proq tarkibga ega bo'lishi kerak; (2) jadval imo-ishoralarni ushlab qoladigan boshqa UIScrollView ichida emas; (3) isScrollEnabled = true; (4) numberOfRowsInSection to'g'ri sonni qaytaradi. Odatiy muammo — estimatedRowHeight holda heightForRowAt = UITableView.automaticDimension, bu cheksiz balandlik hisoblashiga olib keladi.
reloadData() o'rniga performBatchUpdates yoki DiffableDataSource dan foydalaning. reloadData() animatsiyasiz to'liq qayta yuklashni keltirib chiqaradi, vizual miltillashni yaratadi. Nuqtali yangilash uchun foydalaning: reloadRows(at:with:), insertRows, deleteRows. performBatchUpdates ichidagi barcha o'zgarishlar bir vaqtda animatsiya qilinadi. DiffableDataSource buni qo'lda chaqiruvlarsiz avtomatik qiladi.
UITableView — oldindan belgilangan hujayra uslublari va o'rnatilgan tahrirlash bilan bir ustunli vertikal ro'yxat. UICollectionView — elementlarning ixtiyoriy joylashuvi bilan moslashuvchan maket (grid, ro'yxat, karusel, kaskad). Oddiy ro'yxatlar uchun UITableView ni tanlang (sozlamalar, kontaktlar, xabarlar). Galereyalar, kataloglar, doskalar va har qanday chiziqli bo'lmagan maketlar uchun UICollectionView ni tanlang.
tableView.tableFooterView = UIView(frame: .zero) ni o'rnating. Standart bo'yicha, UITableView oxirgi elementdan pastki chetigacha bo'sh qatorlarni (ajratgichlarni) ko'rsatadi. tableFooterView da bo'sh UIView o'rnatish ularni olib tashlaydi. Grouped-uslub uchun bu talab qilinmaydi — jadval faqat oxirgi bo'limning yumaloq burchaklari bilan haqiqiy qatorlarni ko'rsatadi.
tableView.rowHeight = 80 va tableView.estimatedRowHeight = 0 ni o'rnating yoki estimatedRowHeight ni tashlab keting. Doimiy balandlik bilan UITableView heightForRowAt ni chaqirmaydi, bu 100+ elementli ro'yxatlar uchun renderlashni 5–10 marta tezlashtiradi. Maxsus balandlikdagi hujayralar (turli tarkib) uchun self-sizing dan foydalaning: estimatedRowHeight + UITableView.automaticDimension.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.