#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
. Так что, если это не важно для вас (или не так), и вам не нужно соблюдать это на этом уровне, вы можете использовать обычное объявление свойства.