#ios #swiftui #ios14
#iOS #swiftui #ios14
Вопрос:
Мне нужна помощь в поиске наилучшего способа поддержки нового @StateObject в iOS 14.0 и по-прежнему поддерживает некоторую альтернативу в iOS 13.0. По общему признанию, я не знаю, какой наилучший подход в iOS 13.0. Ниже то, что у меня есть в настоящее время.
У кого-нибудь есть идеи по лучшему подходу?
struct HomeView: View {
let viewModel: HomeViewModel
var body: some View {
if #available(iOS 14, *) {
HomeViewWrapper(viewModel: viewModel)
} else {
CompatibleHomeViewWrapper(viewModel: viewModel)
}
}
}
@available(iOS 14, *)
private struct HomeViewWrapper: View {
@StateObject var viewModel: HomeViewModel
var body: some View {
CompatibleHomeView(viewModel: viewModel)
}
}
private struct CompatibleHomeViewWrapper: View {
@State var viewModel: HomeViewModel
var body: some View {
CompatibleHomeView(viewModel: viewModel)
}
}
struct CompatibleHomeView: View {
@ObservedObject var viewModel: HomeViewModel
var body: some View {
Text(viewModel.someRandomName)
}
}
Комментарии:
1. Использование
@ObservedObject
очень похоже и поддерживается в iOS 132. На самом деле в таком случае я вообще не вижу необходимости в HomeViewWrapper. Оболочка StateObject необходима, когда объект создается внутри, но у вас есть внешнее владение, даже вне родительского представления, поэтому объект состояния не нужен, поскольку HomeViewModel не воссоздается при перестроении представления.
3. @loremipsum. Да,
@ObservedObject
похоже, но во всей документации Apple и в видеороликах WWDC это то, что мы не должны использовать.@ObservedObject
используется только тогда, когда у нас есть право собственности на ресурс.4. @Asperi. Хотя HomeView не создает HomeViewModel, он имеет право собственности на него. HomeViewModel создается и передается в HomeView, который затем будет владеть им.
Ответ №1:
Вы можете получить поведение @StateObject, обернув пользовательскую оболочку свойств вокруг @State и @ObservedObject следующим образом:
import Combine
import PublishedObject // https://github.com/Amzd/PublishedObject
/// A property wrapper type that instantiates an observable object.
@propertyWrapper
public struct StateObject<ObjectType: ObservableObject>
where ObjectType.ObjectWillChangePublisher == ObservableObjectPublisher {
/// Wrapper that helps with initialising without actually having an ObservableObject yet
private class ObservedObjectWrapper: ObservableObject {
@PublishedObject var wrappedObject: ObjectType? = nil
init() {}
}
private var thunk: () -> ObjectType
@ObservedObject private var observedObject = ObservedObjectWrapper()
@State private var state = ObservedObjectWrapper()
public var wrappedValue: ObjectType {
if state.wrappedObject == nil {
// There is no State yet so we need to initialise the object
state.wrappedObject = thunk()
}
if observedObject.wrappedObject == nil {
// Retrieve the object from State and observe it in ObservedObject
observedObject.wrappedObject = state.wrappedObject
}
return state.wrappedObject!
}
public init(wrappedValue thunk: @autoclosure @escaping () -> ObjectType) {
self.thunk = thunk
}
}
Я тоже использую это, поэтому буду обновлять его по адресу:
https://gist.github.com/Amzd/8f0d4d94fcbb6c9548e7cf0c1493eaff
Примечание: Наиболее одобренный комментарий заключался в том, что ObservedObject был очень похож, что совсем не соответствует действительности.
StateObject
сохраняет объект между инициализациями представления и передает изменения объекта в представление через willChangeObserver.
ObservedObject
только передает изменения в представление, НО если вы создаете его в инициализации представления, каждый раз, когда изменяется родительский вид, объект будет инициализироваться снова (теряя ваше состояние).
Это объяснение очень грубое, и, пожалуйста, ознакомьтесь с ним, поскольку оно является важной частью SwiftUI.