Сбой при использовании перечисления со связанными значениями

Вот как я инициализирую контейнер модели:

import SwiftUI
import SwiftData
@main
struct MyApp: App {
    let modelContainer: ModelContainer
    init() {
        do {
            modelContainer = try ModelContainer(for: MyModel.self)
        } catch {
            fatalError("Could not initialize ModelContainer")
        }
    }
    var body: some Scene {
        WindowGroup {
            ContentView()
                .modelContainer(modelContainer)

        }
    }
}

и это остальная часть кода, которая может воспроизвести проблему:

import SwiftUI
import SwiftData

enum DayOfWeek: Identifiable, Hashable, Codable {
    var id: Self { self }
    case sunday, monday, tuesday, wednesday, thursday, friday, saturday
}

enum FrequencyType: Identifiable, Hashable, Codable {
    var id: Self { self }
    case daily(interval: Int)
    case specificDaysOfWeek([DayOfWeek])
}

@Model
final class MyModel: Identifiable {

    init() {
        self.frequency = .daily(interval: 1)
    }

    @Attribute(.unique)
    private(set) var id: String = UUID().uuidString
    private(set) var frequency: FrequencyType

    func setFrequency(_ frequency: FrequencyType) {
        self.frequency = frequency
    }
}

struct ContentView: View {
   
    @Environment(\.modelContext) private var modelContext

    private let model = MyModel()

    var body: some View {
        Text("Content View")
            .onAppear {
                modelContext.insert(model)
                model.setFrequency(.specificDaysOfWeek([.friday, .monday]))
            }
    }
}

происходит то, что когда я делаю что-то вроде:

model.setFrequency(.specificDaysOfWeek([.friday, .monday]))

приложение вылетает с такой ошибкой:

CoreData: ошибка: SQLCore sendRequest: запрос на обработку исключений: <NSSQLSaveChangesRequestContext: 0x60000374c300> , [<Foundation.__NSSwiftData 0x600000c6e8b0> valueForUndefinedKey:]: этот класс не соответствует кодированию значений ключей для ключа _buffer. с информация пользователя { NSTargetObjectUserInfoKey = {длина = 29, байт = 0x5b7b2266 72696461 79223a7b 7d7d2c7b ... 6179223a 7b7d7d5d }; NSUnknownUserInfoKey = "_buffer"; }

Я не понимаю, откуда это _buffer и почему происходит сбой?

Обновлено:

Вот что я получу, если включу отладку Core Data (уровень 3):

Кодировка .specificDaysOfWeek([.friday, .monday]) дает {"specificDaysOfWeek":{"_0":[{"friday":{}},{"monday":{}}]}}. Я предполагаю, что _0, который вы видите в json, — это _buffer.

Timmy 22.04.2024 11:15

Структуры SwiftUI, такие как App и View, не должны создавать объекты типа ModelContainer в своей инициализации или теле. Вам нужно переместить его в действие типа onAppear, иначе это утечка памяти и в вашем случае выглядит как сбой. Альтернативно воспользуйтесь функцией удобства .modelContainer(for: MyModel.self), которая доставит объект в нужное для вас время.

malhal 22.04.2024 11:56

@malhal Если вы попытаетесь использовать то, что вы предложили, вы увидите ошибку: Fatal error: failed to find a currently active container for MyModel. Вот почему я инициализировал его таким образом, просто чтобы создать минимальный воспроизводимый пример. Однако спасибо за подсказки, однако суть этого вопроса заключалась в сбое SwiftData, а не в архитектуре приложения и лучших практиках.

Whirlwind 22.04.2024 12:07

Поскольку это происходит на уровне основных данных/sql, вы можете включить ведение журнала отладки основных данных и посмотреть, покажет ли это что-нибудь интересное.

Joakim Danielson 22.04.2024 12:07

@Тимми Итак, что вы предлагаете, какую-то специальную кодировку для перечисления FrequencyType?

Whirlwind 22.04.2024 12:08

@JoakimDanielson Я включил это, но мне это не помогло. Я могу разместить это здесь... Секундочку.

Whirlwind 22.04.2024 12:08

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

Joakim Danielson 22.04.2024 13:08

@JoakimDanielson Это все, что я вижу в консоли, когда запускаю этот код :(

Whirlwind 22.04.2024 13:16

Тогда я предполагаю, что это внутренний сбой в Core Date перед попыткой сохранения данных. Посмотрим, смогу ли я воспроизвести это сам.

Joakim Danielson 22.04.2024 13:27
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
129
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

После исследования и отладки этой проблемы я пришел к выводу, что это происходит при генерации SQL, связанного со свойством, а также что кодирование свойства работает должным образом, поэтому я могу только предположить, что это ошибка/не поддерживается, поскольку нет вмешательства пользовательского кода. в процессе.

Обходным решением этой проблемы может быть превращение свойства перечисления в вычисляемое свойство, а затем использование структуры для частного свойства, которое сохраняется вместо перечисления. Это означает наличие дополнительного типа и некоторого связующего кода, но общедоступный API останется прежним, поэтому, когда эта проблема будет исправлена ​​в SwiftData, нужно будет перенести только модель.

struct InternalFrequencyType: Codable {
    let interval: Int?
    let daysOfWeek: [DayOfWeek]?

    init(frequencyType: FrequencyType) {
        switch frequencyType {
        case .daily(let interval):
            self.interval = interval
            daysOfWeek = nil
        case .specificDaysOfWeek(let array):
            daysOfWeek = array
            interval = nil
        }
    }

    var toFrequencyType: FrequencyType {
        if let interval {
            return .daily(interval: interval)
        } else {
            //alternatively to '?? []' use forced unwrapping or throw an error 
            return .specificDaysOfWeek(daysOfWeek ?? [])
        }
    }
}

Тогда изменения в модели будут

private var internalFrequencyType: InternalFrequencyType
var frequency: FrequencyType {
    get { internalFrequencyType.toFrequencyType }
    set { internalFrequencyType = .init(frequencyType: newValue) }
}

и в init

internalFrequencyType = .init(frequencyType: .daily(interval: 1))

Спасибо, это сработало так. И да, в момент разговора это кажется чем-то неподдерживаемым...

Whirlwind 22.04.2024 19:30

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