Причины использования оболочки свойств @StateObject в структуре приложения SwiftUI?

#swiftui

#swiftui

Вопрос:

Это из документации Apple по протоколу приложения SwiftUI:

 @main
struct Mail: App {
    @StateObject private var model = MailModel()

    var body: some Scene {
        WindowGroup {
            MailViewer()
                .environmentObject(model) // Passed through the environment.
        }
        Settings {
            SettingsView(model: model) // Passed as an observed object.
        }
    }
}
  

Почему в этом случае нам нужно использовать оболочку свойств @StateObject? Почему обычного свойства недостаточно?

Я подозреваю, что структура «App» является объектом конфигурации, как и представления в SwiftUI? И что мы не можем рассчитывать на то, что эта структура будет висеть после прочтения тела? Правильно?

Ответ №1:

Основная причина заключается в том, что для предварительного просмотра модели, которые инициализируются, @StateObject не инициализируются. WWDC 2020 Структурируйте свое приложение для предварительного просмотра SwiftUI 8:19

Во-вторых, изменения модели @StateObject позволят SwiftUI обнаружить изменение и вызвать body повторное вычисление, поскольку на модель ссылаются (дважды) в теле, что SwiftUI знает по отслеживанию зависимостей. Это означает, что MailViewer and SettingsView будет воссоздан с новыми данными в модели. Затем, если что-то изменилось в этих структурах представления, SwiftUI обнаружит это, отличая новые структуры от ранее возвращенных, и обновит экран любыми изменениями, необходимыми для обновления экрана.

Как вы говорите, мы не можем гарантировать, что структуры будут зависать, на самом деле это не так, они создаются, экран отображается, и они выбрасываются. Вот почему мы используем оболочки свойств, поэтому при повторном создании структуры ей предоставляются те же данные, которые используются для свойства. В случае @StateObject , если объект создается один раз, тело вычисляется в первый раз из первой структуры. Если структура больше не создается, например, она исключается с помощью оператора if, тогда объект деинфицируется. Если структура будет создана снова в будущем, то будет создан новый объект, это скорее функция для представлений, чем для приложений. Это означает, что жизненный цикл объекта состояния привязан к жизненному циклу представления, отображаемого на экране, что является очень мощным.

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

Комментарии:

1. Спасибо @malhal за ваш ответ. StateObject имеет смысл для меня, когда используется глубже в иерархии представлений, потому что я ожидаю, что эти представления будут воссоздаваться много раз. Но я не уверен, что полностью понимаю использование в структуре корневого приложения. Будет ли эта корневая структура воссоздаваться много раз?

2. Я думаю, лучше предположить, что AppStruct будет воссоздан, даже если прямо сейчас трудно найти ситуацию, когда это может произойти. Это то же самое, что и в SwiftUI v1.0. мы не думали, что корневой contentView когда-либо будет воссоздан, но теперь у нас есть приложение и сцена. 2 основные причины использования @StateObject в структуре приложения — это инициализация объекта непосредственно перед запуском тела, а не при инициализации структуры (что позволяет SwiftUI сохранять объект в правильном месте), и что при изменении объекта тело приложения пересчитывается.

Ответ №2:

Согласно Apple @StateObject , гарантирует, что model в

 @StateObject private var model = MailModel()
  

будет создан только один раз. Это все отличие от @ObservedObject . Так что, если это не важно для вас (или не так), и вам не нужно соблюдать это на этом уровне, вы можете использовать обычное объявление свойства.