SwiftUI множественные привязки - PullRequest
2 голосов
/ 18 февраля 2020

У меня есть контроллер MasterView, который содержит список и мой контроллер детального просмотра. Контроллер подробных представлений будет редактировать информацию о наборе данных, выбранном в MasterView.

Насколько я понимаю, мне придется создать привязку в моей детали, поэтому, когда я редактирую детали, детали также должны измениться в моем списке MasterView.

Как правильно это сделать? Мой подробный вид также состоит из нескольких видов, где производится редактирование. Должен ли я получить информацию, имеющую обязательную силу для всех моих низших взглядов? Могу ли я go из @State -> @Binding -> @Binding, и все же первое состояние изменится?

Я использую SwiftUI для MacOS.

Вот как это выглядит (слева от списка и справа от правки Вид)

1 Ответ

2 голосов
/ 18 февраля 2020

для чего-либо более сложного, например простого State / Binding, для визуального изменения некоторых компонентов вашего пользовательского интерфейса, go вперед и использования @ObservableObject / @ObservedObject или для действительно глобального обмена @EnviromentObject вместо @State / @Binding. Поместите все логи c в вашу модель, не пытайтесь сделать это в вашем SwiftUI. Это избавит вас от многих проблем, поиска ошибок и т. Д. c.

ОБНОВЛЕНИЕ Нет лучшего способа, чем просмотр документации

/// A linked View property that reads a `ObservableObject` supplied by an
/// ancestor view that will automatically invalidate its view when the object
/// changes.
///
/// - Precondition: A model must be provided on an ancestor view by calling
///     `environmentObject(_:)`.
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
@propertyWrapper public struct EnvironmentObject<ObjectType> : DynamicProperty where ObjectType : ObservableObject {

    /// A wrapper of the underlying `ObservableObject` that can create
    /// `Binding`s to its properties using dynamic member lookup.
    @dynamicMemberLookup public struct Wrapper {

        /// Creates a `Binding` to a value semantic property of a
        /// reference type.
        ///
        /// If `Value` is not value semantic, the updating behavior for
        /// any views that make use of the resulting `Binding` is
        /// unspecified.
        public subscript<Subject>(dynamicMember keyPath: ReferenceWritableKeyPath<ObjectType, Subject>) -> Binding<Subject> { get }
    }

    /// The current model supplied by an ancestor view.
    @inlinable public var wrappedValue: ObjectType { get }

    public var projectedValue: EnvironmentObject<ObjectType>.Wrapper { get }

    public init()
}

Используйте его, если вычислены все свойства @Published свойства et c. являются общими.

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

/// A dynamic view property that subscribes to a `ObservableObject` automatically invalidating the view
/// when it changes.
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
@propertyWrapper public struct ObservedObject<ObjectType> : DynamicProperty where ObjectType : ObservableObject {

    /// A wrapper of the underlying `ObservableObject` that can create
    /// `Binding`s to its properties using dynamic member lookup.
    @dynamicMemberLookup public struct Wrapper {

        /// Creates a `Binding` to a value semantic property of a
        /// reference type.
        ///
        /// If `Value` is not value semantic, the updating behavior for
        /// any views that make use of the resulting `Binding` is
        /// unspecified.
        public subscript<Subject>(dynamicMember keyPath: ReferenceWritableKeyPath<ObjectType, Subject>) -> Binding<Subject> { get }
    }

    public init(initialValue: ObjectType)

    public init(wrappedValue: ObjectType)

    public var wrappedValue: ObjectType

    public var projectedValue: ObservedObject<ObjectType>.Wrapper { get }
}

и, наконец, вам нужна модель, которая должна соответствовать

/// A type of object with a publisher that emits before the object has changed.
///
/// By default an `ObservableObject` will synthesize an `objectWillChange`
/// publisher that emits before any of its `@Published` properties changes:
///
///     class Contact: ObservableObject {
///         @Published var name: String
///         @Published var age: Int
///
///         init(name: String, age: Int) {
///             self.name = name
///             self.age = age
///         }
///
///         func haveBirthday() -> Int {
///             age += 1
///             return age
///         }
///     }
///
///     let john = Contact(name: "John Appleseed", age: 24)
///     john.objectWillChange.sink { _ in print("\(john.age) will change") }
///     print(john.haveBirthday())
///     // Prints "24 will change"
///     // Prints "25"
///
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol ObservableObject : AnyObject {

    /// The type of publisher that emits before the object has changed.
    associatedtype ObjectWillChangePublisher : Publisher = ObservableObjectPublisher where Self.ObjectWillChangePublisher.Failure == Never

    /// A publisher that emits before the object has changed.
    var objectWillChange: Self.ObjectWillChangePublisher { get }
}

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension ObservableObject where Self.ObjectWillChangePublisher == ObservableObjectPublisher {

    /// A publisher that emits before the object has changed.
    public var objectWillChange: ObservableObjectPublisher { get }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...