Azimjon Abdurasulov

UIKit 2: Layout va render sikli — runloop, updateProperties, Auto Layout va 120 Hz

📱 UIKit va SwiftUI — chuqur

UIKit 2: Layout va render sikli — runloop, updateProperties, Auto Layout va 120 Hz

Holat: 2026-yil sentabr. iOS ilovalarda animatsiyalarning qotishi (stutter) va xatoliklar asosan Run Loop va render siklini noto'g'ri tushunishdan kelib chiqadi. Ushbu darsda cheklovlar (constraints), joylashuv (layout) va chizish (display) bosqichlari, setNeedsLayout ning coalescing mexanizmi, iOS 26 da qo'shilgan yangi updateProperties metodi hamda 120 Hz ProMotion talablari ko'rib chiqiladi.

Mundarija

  1. Run Loop va render siklining 3 bosqichi
  2. Coalescing: setNeedsLayout va layoutIfNeeded mexanizmi
  3. iOS 26 yangiligi: updateProperties va uning tartibi
  4. Auto Layout anatomiyasi: Hugging va Compression Resistance
  5. Intrinsic Content Size va dinamik o'lchamlar
  6. Display pass: draw(_:) dan qachon qochish kerak?
  7. 120 Hz ProMotion displeylari va CADisplayLink
  8. Xulosa
  9. Manbalar

1. Run Loop va render siklining 3 bosqichi {#render-loop}

Foydalanuvchi ekranga tekkanda yoki tarmoqdan ma'lumot kelganda, UIKit darhol ekranni qayta chizmaydi. Har bir Run Loop aylanmasining oxirida Render Loop ishga tushadi:

[Run Loop hodisasi] (Teginish, Timer, Tarmoq)
        |
        v
+-------------------------------------------------------+
| 1. Constraints Pass: updateConstraints()              |
|    (Cheklovlar hisob-kitobi: yuqoridan pastga)        |
+-------------------------------------------------------+
        |
        v
+-------------------------------------------------------+
| 2. Layout Pass: updateProperties() -> layoutSubviews()|
|    (Frame va bounds o'rnatilishi: pastdan yuqoriga)   |
+-------------------------------------------------------+
        |
        v
+-------------------------------------------------------+
| 3. Display Pass: draw(_:) / CoreAnimation Commit      |
|    (Piksellarni GPU'ga uzatish va ekranga chiqarish)  |
+-------------------------------------------------------+

RunLoop va Render Siklining 3 Bosqichi


2. Coalescing: setNeedsLayout va layoutIfNeeded mexanizmi {#coalescing}

iOS samaradorligining siri — birlashtirish (coalescing) qobiliyatidadir.

Haqiqiy o'lchov natijalari (iOS 26.5 simulyatorida CountingView):

  • Agar setNeedsLayout() chaqirilmagan bo'lsa, layoutIfNeeded() chaqirilganda qo'shimcha layoutSubviews() chaqiruvi soni: **0**.
  • Agar ketma-ket **3 marta setNeedsLayout()** chaqirilib, so'ng layoutIfNeeded() bajarilsa, layoutSubviews() chaqiruvi soni: **1 marta**!
import UIKit

@MainActor
func demonstrateCoalescing(view: UIView) {
  // Bu chaqiruvlar 3 marta qayta chizishga olib kelmaydi:
  view.setNeedsLayout()
  view.setNeedsLayout()
  view.setNeedsLayout()

  // Faqat 1 marta barcha o'zgarishlar bitta siklda bajariladi:
  view.layoutIfNeeded()
}
  • **setNeedsLayout():** "Men kirlendim (dirty), keyingi freymda meni qayta hisobla" deb bayroqcha qo'yadi. Juda tez va yengil amal.
  • **layoutIfNeeded():** Agar dirty bayrog'i bo'lsa, Run Loop oxirini kutmasdan darhol shu zahoti layoutSubviews() ni chaqiradi. Animatsiya bloklari ichida (UIView.animate) frame o'zgarishini majburiy kiritish uchun aynan layoutIfNeeded() ishlatiladi.

3. iOS 26 yangiligi: updateProperties va uning tartibi {#update-properties}

iOS 26.0 (Xcode 26.5) bilan UIKit'ga yangi **updateProperties** API'si qo'shildi (sdk_facts.md):

  • setNeedsUpdateProperties()
  • updateProperties() (talab: super.updateProperties() chaqirilishi shart)
  • updatePropertiesIfNeeded()

Ushbu metod view xususiyatlarini (ranglar, matnlar, holatlar) layout hisobidan ajratish uchun xizmat qiladi.

O'lchangan tartib (iOS 26.5 simulyatori):

Ikkala bayroqcha ham yoqilganda (setNeedsUpdateProperties() va setNeedsLayout()), layoutIfNeeded() bajarilganda chaqirilish tartibi:

$$\text{Order} = [\text{"updateProperties"}, \text{"layoutSubviews"}]$$

updateProperties() doimo **layoutSubviews() dan oldin** bajariladi! Bu view o'z xususiyatlariga (masalan, matn uzunligiga) qarab o'lchamlarini hisoblab olishi uchun qulaydir.


4. Auto Layout anatomiyasi: Hugging va Compression Resistance {#auto-layout}

Auto Layout tizimi Cassowary chiziqli tengsizliklar algoritmi asosida ishlaydi. Ikkita qarama-qarshi kuch mavjud:

Prioritet turiStandart qiymatMa'nosiXulq-atvori
Content Hugging Priority (CHP)250 (Low)"Meni o'z o'lchamimdan kattalashtirib yuborma"Agar ikkita label qatorda tursa, CHP yuqori bo'lgani o'z o'lchamida qoladi, past bo'lgani esa cho'ziladi.
Content Compression Resistance (CCRP)750 (High)"Meni o'z o'lchamimdan kichiklashtirma, matnimni kesma"Agar joy yetishmasa, CCRP yuqori bo'lgan label to'liq ko'rinadi, past bo'lgani esa uch nuqta (...) bo'lib qisqaradi.
import UIKit

@MainActor
func configureLabelPriorities(titleLabel: UILabel, badgeLabel: UILabel) {
  // Badge doimo o'z hajmida qolishi va cho'zilmasligi shart:
  badgeLabel.setContentHuggingPriority(.required, for: .horizontal)
  badgeLabel.setContentCompressionResistancePriority(.required, for: .horizontal)

  // Title bo'sh joy qolmasa qisqarishi mumkin:
  titleLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
  titleLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
}

5. Intrinsic Content Size va dinamik o'lchamlar {#intrinsic-size}

**intrinsicContentSize** — view o'zining ichki mazmuniga qarab qanday hajm egallashni xohlashini bildiradi (masalan, UILabel matn hajmiga, UIImageView esa rasm piksellariga qarab).

Agar o'zgaruvchi komponent qursangiz:

import UIKit

public final class RoundedBadgeView: UIView {
  public var text: String = "" {
    didSet {
      // Auto Layout'ga ichki hajm o'zgarganini xabar qilamiz:
      invalidateIntrinsicContentSize()
    }
  }

  public override var intrinsicContentSize: CGSize {
    let size = (text as NSString).size(withAttributes: nil)
    return CGSize(width: size.width + 16, height: size.height + 8)
  }
}

6. Display pass: draw(_:) dan qachon qochish kerak? {#display-pass}

draw(_:) metodini qayta yozish (override qilish) eng oxirgi chora bo'lishi kerak.

Nega?

  • draw(_:) chaqirilganda, iOS xotirada ekranning to'liq o'lchamiga mos Backing Store (RGBA bitmap) ochadi. Masalan, iPhone 17 Pro Max ekranida ($1320 \times 2868$ piksel) bitta butun ekranli view $15\text{ MB}$ dan ortiq toza RAM yeydi!
  • CALayer xususiyatlari (backgroundColor, cornerRadius, borderWidth, shadowPath) esa GPU darajasida hech qanday qo'shimcha xotira sarflamasdan ishlaydi.

Faqat CoreGraphics orqali maxsus matematik grafiklar yoki egri chiziqlar (Bezier Path) chizish zarur bo'lgandagina draw(_:) ishlatilishi kerak.


7. 120 Hz ProMotion displeylari va CADisplayLink {#promotion}

Zamonaviy iPhone (Pro modellari) va iPad qurilmalari ProMotion texnologiyasiga ega:

  • 60 Hz displeylar: Freym vaqti — $16.6\text{ ms}$.
  • 120 Hz displeylar: Freym vaqti — atigi $8.3\text{ ms}$!

Agar sizning layoutSubviews() yoki hisob-kitoblaringiz $8.3\text{ ms}$ dan oshib ketsa, qurilma darhol kadrni tashlab yuboradi (dropped frame) va animatsiya qotadi.

Maxsus silliq animatsiyalar uchun **CADisplayLink** dan foydalaniladi:

import UIKit

public final class AnimationDriver: NSObject {
  private var displayLink: CADisplayLink?

  public func start() {
    displayLink = CADisplayLink(target: self, selector: #selector(step))
    // 120 Hz gacha tezlikni so'raymiz:
    displayLink?.preferredFrameRateRange = CAFrameRateRange(
      minimum: 60,
      maximum: 120,
      preferred: 120
    )
    displayLink?.add(to: .main, forMode: .common)
  }

  @objc private func step(link: CADisplayLink) {
    // link.targetTimestamp - keyingi kadr vaqti
  }

  public func stop() {
    displayLink?.invalidate()
    displayLink = nil
  }
}

8. Xulosa {#xulosa}

  • Render Loop uchta qat'iy bosqichdan iborat: Constraints Pass -> Layout Pass -> Display Pass.
  • setNeedsLayout() chaqiruvlari coalescing orqali birlashtiriladi va bitta freymda faqat bir marta layoutSubviews() bajariladi.
  • iOS 26 ning updateProperties() metodi view holatini layoutdan ajratadi va doimo layoutSubviews() dan oldin chaqiriladi.
  • Auto Layout'da Content Hugging cho'zilmaslikni, Compression Resistance esa qisqarmaslikni boshqaradi.
  • draw(_:) ortiqcha xotira (backing store) sarflagani tufayli, iloji boricha CALayer xususiyatlaridan foydalanish zarur.
  • 120 Hz ProMotion sharoitida har bir freym $8.3\text{ ms}$ dan kam vaqtda bajarilishi shart.

Manbalar {#manbalar}

  1. Auto Layout Guide — Apple Documentation Archive
  2. UIView layoutSubviews() — Apple Documentation
  3. Optimizing ProMotion Performance — Apple Documentation
  4. High Performance Auto Layout — WWDC

Markdown manba

iOS Lessons