Двусторонняя привязка SwiftUI к значению внутри ObservableObject внутри случая перечисления - PullRequest
3 голосов
/ 26 мая 2020

Я пытаюсь наблюдать изменения значения bool, содержащегося в ObservableObject, которое является значением в случае enum. Вот пример того, чего я пытаюсь достичь, но при текущем подходе я получаю сообщение об ошибке Use of unresolved identifier '$type1Value'.

import SwiftUI
import Combine

class ObservableType1: ObservableObject {
    @Published var isChecked: Bool = false
}

enum CustomEnum {
    case option1(ObservableType1)
}

struct Parent: View {
    var myCustomEnum: CustomEnum
    var body: AnyView {
        switch myCustomEnum {
        case .option1(let type1Value):
            AnyView(Child(isChecked: $type1Value.isChecked)) // <- error here
        }
    }
}

struct Child: View {
    @Binding var isChecked: Bool
    var body: AnyView {
        AnyView(
            Image(systemName: isChecked ? "checkmark.square" : "square")
            .onTapGesture {
                self.isChecked = !self.isChecked
        })
    }
}

Я пытаюсь обновить значение isChecked из интерфейса, но поскольку я хотите иметь ObservableObject, который содержит свойство в enum, например, CustomEnum, не знаю, как это сделать и возможно ли это. Я выбрал перечисление, потому что будет несколько вариантов перечисления с разными значениями ObservableObject, а Parent будет генерировать разные подпредставления в зависимости от параметра CustomEnum. Если это имеет какое-либо значение, Parent получит значение myCustomEnum из Array из CustomEnum значений. Это вообще возможно? Если нет, то какие у меня есть альтернативы? Спасибо!

Ответы [ 2 ]

1 голос
/ 26 мая 2020

Ну, никогда не говори никогда ... Я нашел интересное решение для этого сценария, которое даже позволяет удалить AnyView. Протестировано с помощью Xcode 11.4 / iOS 13.4

На всякий случай предоставлен полный тестируемый модуль.

// just for test
struct Parent_Previews: PreviewProvider {
    static var previews: some View {
        Parent(myCustomEnum: .option1(ObservableType1()))
    }
}

// no changes
class ObservableType1: ObservableObject {
    @Published var isChecked: Bool = false
}

// no changes
enum CustomEnum {
    case option1(ObservableType1)
}

struct Parent: View {
    var myCustomEnum: CustomEnum

    var body: some View {
        self.processCases() // function to make switch work
    }

    private func processCases() -> some View {
        switch myCustomEnum {
        case .option1(let type1Value):
            // main part !!
            return ObservedHolder(value: type1Value) { object in
                Child(isChecked: object.isChecked)
            }
        }
    }
}

// just remove AnyView
struct Child: View {
    @Binding var isChecked: Bool
    var body: some View {
        Image(systemName: isChecked ? "checkmark.square" : "square")
            .onTapGesture {
                self.isChecked = !self.isChecked
            }
    }
}

Вот плеймейкер

struct ObservedHolder<T: ObservableObject, Content: View>: View {
    @ObservedObject var value: T
    var content: (ObservedObject<T>.Wrapper) -> Content

    var body: some View {
        content(_value.projectedValue)
    }
}
0 голосов
/ 26 мая 2020

Это может сработать в вашем случае:

import SwiftUI

class ObservableType1: ObservableObject {
    @Published var isChecked: Bool = false
}

enum CustomEnum {
    case option1(ObservableType1)
}

struct Parent: View {
    var myCustomEnum: CustomEnum
    var body: AnyView {
        switch (myCustomEnum) {
            case .option1:
                return AnyView(Child())
            default: return AnyView(Child())
        }
    }
}

struct Child: View {

    @ObservedObject var type1 = ObservableType1()

    var body: AnyView {
        AnyView(
            Image(systemName: self.type1.isChecked ? "checkmark.square" : "square")
            .onTapGesture {
                self.type1.isChecked.toggle()
        })
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...