0Pricing
Swift Academy · Урок

Кэш компоновки и производительность

Используйте кэш компоновки для повышения эффективности.

«Кэш компоновки и производительность» — бесплатный урок Swift Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.

Зачем нужен кэш макета?

SwiftUI может многократно вызывать sizeThatFits и placeSubviews в течение одного прохода макета.

Если вычисления требуют много ресурсов, кэш позволяет выполнить их один раз и повторно использовать результат, избегая лишней работы.

Связанный тип кэша

Протокол Layout имеет связанный тип Cache, по умолчанию равный Void. Определите собственную структуру для хранения предварительно вычисленных результатов.

struct FlowLayout: Layout {
    struct CacheData {
        var sizes: [CGSize] = []
    }
    typealias Cache = CacheData
}

makeCache

Реализуйте makeCache(subviews:), чтобы создать исходный кэш. SwiftUI вызывает его один раз перед методами макета, предоставляя место для предварительного измерения.

func makeCache(subviews: Subviews) -> CacheData {
    let sizes = subviews.map { $0.sizeThatFits(.unspecified) }
    return CacheData(sizes: sizes)
}

Чтение кэша

Теперь методы макета получают cache как параметр inout. Читайте предварительно вычисленные значения вместо повторного измерения каждого дочернего представления.

func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout CacheData) -> CGSize {
    let height = cache.sizes.map(\.height).max() ?? 0
    let width = cache.sizes.reduce(0) { $0 + $1.width }
    return CGSize(width: width, height: height)
}

updateCache

Когда набор дочерних представлений изменяется, SwiftUI вызывает updateCache(_:subviews:). Реализация по умолчанию пересоздаёт кэш через makeCache, но Вы можете переопределить её для постепенного обновления.

func updateCache(_ cache: inout CacheData, subviews: Subviews) {
    cache.sizes = subviews.map { $0.sizeThatFits(.unspecified) }
}

Когда вызывается updateCache

updateCache выполняется при изменении количества или идентичности дочерних представлений, но не при каждом изменении геометрии. Кэшируйте только данные, зависящие от дочерних представлений, а не от предложенного размера.

Кэшируйте только данные, не зависящие от предложения

Распространённая ошибка — кэшировать результаты, зависящие от предложенного размера. Предложение может измениться между вызовами, поэтому результаты, зависящие от размера, необходимо вычислять заново, а не бездумно кэшировать.

// OK to cache: intrinsic child sizes
// NOT OK to cache: row breaks (depend on proposed width)

Кэширование собственных размеров

Безопасный подход — кэшировать требующие больших затрат результаты sizeThatFits(.unspecified), а затем при каждом вызове выполнять недорогие вычисления переноса с текущим предложением.

struct CacheData { var intrinsic: [CGSize] = [] }
// wrapping uses cache.intrinsic + current maxWidth

Избегайте преждевременной оптимизации

Для небольшого количества простых дочерних представлений измерение выполняется быстро, а кэш усложняет код. Сначала измерьте производительность; используйте кэш только тогда, когда измерение действительно требует много ресурсов: например, для текста, изображений или вложенных макетов.

Кэш и семантика значений

Кэш принадлежит SwiftUI и передаётся как inout. Храните его как обычный тип значения без ссылок на представления, чтобы SwiftUI мог безопасно управлять сроком его существования.

struct CacheData {
    var sizes: [CGSize] // value types only
}

Оценка эффективности

Используйте инструмент SwiftUI или простые счётчики, чтобы убедиться, что кэш действительно сокращает количество измерений. Оптимизация без измерений — это лишь догадки.

Быстрая проверка: кэш макета

Проверьте понимание кэширования макета.

Итоги: кэш макета и производительность

Связанный тип Cache протокола Layout, создаваемый с помощью makeCache и обновляемый с помощью updateCache, хранит требующую больших затрат работу, не зависящую от предложения, например собственные размеры дочерних представлений.

Выполняйте недорогие вычисления, зависящие от предложения, при каждом вызове. Храните кэш как тип значения без ссылок, избегайте преждевременного кэширования и перед добавлением сложности проверяйте пользу с помощью профилирования.

Часто задаваемые вопросы

Урок «Кэш компоновки и производительность» бесплатный?

Да — полный текст урока «Кэш компоновки и производительность» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.

Чему я научусь в уроке «Кэш компоновки и производительность»?

Используйте кэш компоновки для повышения эффективности. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Swift Academy?

Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Кэш компоновки и производительность»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Swift Academy?

Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Основы протокола Layout
  2. Измерение подвида
  3. Создание потоковой компоновки
  4. Кэш компоновки и производительность
← Назад к Swift Academy