Почему привязка CoreData NSManagedObject не обновляется при изменении в Swift?

Контекст

У меня есть довольно простой Form, использующий MVVM архитектуру. Однако я столкнулся с проблемой этой реализации. У моего DetailView есть DummyState, который изменяет соответствующий атрибут EntityonChange.

Проблема: как только появляется DetailView, оба Toggles включены, как и ожидалось. Однако при отключении местного Toggle остается включенным другой Toggle, что неожиданно. Однако, как только я взаимодействую с другим элементом (не в MRE), кажется, что второй Toggle обновляется и отключается.


Код

@objc(Entity) public class Entity: NSManagedObject {
    @NSManaged public var enabled: Bool
}

class FormViewModel: ObservableObject, CustomFormObservable {
    @Published var entity = Entity(context: ...)

    init() { self.entity.enabled = true }

    var isValid: Bool { self.entity.enabled }
}

struct FormView: View {
    @StateObject private var formVM = FormViewModel()

    var body: some View {
        CustomForm(formVM: formVM) {
            DetailView(entity: $formVM.entity)
        }
    }
}

struct DetailView: View {
    @Binding var entity: Entity
    @State private var localEnabled: Bool = true

    var body: some View {
        Toggle("Local Toggle", isOn: $localEnabled)
            .onChange(of: localEnabled) { entity.enabled = $0 }

        Toggle("Toggle", isOn: $entity.enabled)
    }
}

Вопрос

  • Что вызывает такое поведение и как я могу его решить?
stackoverflow.com/questions/76211411/…
lorem ipsum 20.05.2023 17:44

Все объекты CoreData должны быть обернуты в ObservedObject, их переменные типа значения могут использовать Binding

lorem ipsum 20.05.2023 18:17

@loremipsum большое спасибо за ваш ответ и ресурс. Для меня это имеет смысл, однако я обновил свой код, а также MRE и столкнулся с другой проблемой. Смотрите текущий ответ и его комментарии. У вас есть какие-либо идеи, что вызывает это?

christophriepe 20.05.2023 18:19

Entity имеет неправильную оболочку, и ваша виртуальная машина не может наблюдать за наблюдаемым объектом. Это лишний ненужный слой.

lorem ipsum 20.05.2023 18:32

@loremipsum Спасибо за ваш ответ. Какую оболочку сущности вы имеете в виду? И как упростить код, убрав слой? Небольшой пример кода был бы очень признателен.

christophriepe 20.05.2023 18:47

Вадиан уже дал тебе код

lorem ipsum 20.05.2023 20:33
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Потому что NSManagedObject — это ссылочный тип.

Есть простое правило:

  • @State и @Binding предназначены для типов значений, таких как структуры.
  • @StateObject и @ObservedObject предназначены для ссылочных типов, таких как классы.

И ссылка на знак доллара также только для типов значений.

К счастью, NSManagedObject по умолчанию соответствует ObservableObject.


struct MainView: View {
    @StateObject private var formVM = FormViewModel()

    var body: some View {
        DetailView(entity: formVM.entity)
    }
}

struct DetailView: View {
    @ObservedObject var entity: Entity
    @State private var localEnabled: Bool = true

    var body: some View {
        Toggle("Local Toggle", isOn: $localEnabled)
            .onChange(of: localEnabled) { entity.enabled = $0 }

        Toggle("Toggle", isOn: $entity.enabled)
    }
}

Большое спасибо за вашу поддержку! Это реализация, которая у меня была раньше. Однако при изменении ObservedObject в DetailView@Published var entity в FormViewModel не обновляется. Именно по этой причине я перешел на Binding. Любая идея о том, как решить эту проблему?

christophriepe 20.05.2023 18:00

Я добавил дополнительный код в файл MRE. У меня также есть вычисляемое свойство isValid, которое используется для проверки того, должна ли кнопка «Сохранить» быть неразрешимой. Когда я сказал в своем предыдущем комментарии, что представление не обновляется, я имел в виду, что кнопка Save не становится интерактивной, даже если условие выполнено.

christophriepe 20.05.2023 18:07

Вместо вычисляемого свойства, которое на самом деле тоже должно быть @Published, используйте formVM.entity.enabled в представлении. Все свойства NSManaged публикуются.

vadian 20.05.2023 19:18

Большое спасибо за ваш ответ, но я не совсем понимаю ваше предложение. CustomForm является общим и принимает ViewModel, соответствующий CustomFormObservable, для которого требуется свойство isValid. У меня нет доступа к конкретному свойству entity изнутри CustomForm, чтобы проверить, должна ли кнопка «Сохранить» быть неразрешимой, эта логика должна быть передана на аутсорсинг.

christophriepe 20.05.2023 19:26

На самом деле это новый вопрос. Мой ответ решает проблему @Binding. Поскольку NSManagedObject соответствует ObservableObject, вы можете реализовать Combine Publisher, который управляет свойством isValid.

vadian 20.05.2023 20:13

Ты прав. Я принял ваш ответ и задал новый вопрос по этой теме: stackoverflow.com/questions/76296952/…

christophriepe 20.05.2023 21:13

Другие вопросы по теме