Как назначить переменную состояния, используя свойства переменной привязки при инициализации представления в SwiftUI

Я пытаюсь использовать свойства переменных @State var и @Binding var в процессе инициализации моего представления, но я не совсем понимаю, является ли способ, которым я это делаю, обычным или «законным» способом, или я просто не могу сделайте это «законным» способом, потому что я не понимаю, как работают @State var и @Binding var.

Это то, чем я сейчас занимаюсь

struct EditPrView: View {

    @State var name: String
    @State var nameCount: Int = 0 // Some value just to initalise the variable

    var body: some View {
        VStack {
            Text(name)
            Text(String(nameCount))
        }.onAppear(perform: { // Do the "actual" assigment here
            nameCount = name.count
        })
    }
}

Это работает хорошо (я еще не сталкивался с проблемами), но кажется «хакерским», и я чувствую, что это можно сделать на этапе инициализации представления.

Это то, что я пробовал

struct EditPrView: View {

    @State var name: String
    @State var nameCount: Int = name.count // This will throw an error

    var body: some View {
        VStack {
            Text(name)
            Text(String(nameCount))
        }
    }
}

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

class A {
    var a: Int = 0
}

class B: A {
    var b: Int = 5
}

struct EditPrView: View {

    @State private var obj: A?
    @State private var count: Int

    init(obj: A?) {
        self.obj = obj
        if obj is B {
            self.count = 2
        } else {
            self.count = 1
        }
    }

    var body: some View {
        VStack {
            Text("foo-bar")
            Text(String(count))
        }
    }
}

#Preview {
    var b: A? = B()
    return EditPrView(obj: b)
}

Это отлично работает, пока я использую только @State в представлении.

class A {
    var a: Int = 0
}

class B: A {
    var b: Int = 5
}

struct EditPrView: View {

    @Binding private var obj: A?
    @State private var count: Int

    init(obj: Binding<A?>) {
        self._obj = obj
        self.count = 0
        if self.obj is B {
            self.count = 2
        } else {
            self.count = 1
        }
    }

    var body: some View {
        VStack {
            Text("foo-bar")
            Text(String(count))
        }
    }
}

#Preview {
    @State var b: A? = B()
    return EditPrView(obj: $b)
}

Но затем я пытаюсь добавить @Binding var вот так, и похоже, что он даже не доходит до оператора else, он просто устанавливает self.count в 0, а затем продолжает отображать представление, даже если экземпляр явно относится к типу B.

Поскольку мне нужен один способ инициализации представления, это заставило меня придерживаться .onAppear(perform: ) способа инициализации переменных, но, как спрашивается, действительно ли это способ сделать это?

TLDR

Почему не срабатывает оператор if в последнем примере блока кода?

stackoverflow.com/questions/77548409/…
lorem ipsum 05.06.2024 00:19
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

В вашем последнем блоке кода if действительно выполняется (вы можете проверить это с помощью отладчика или добавления операторов print), но вы пытаетесь обновить @State несколько раз (сначала до 0, а затем до 1 или 2) во время init, что не поддерживаемый шаблон.

Вместо этого, если вы назначите его один раз, он будет работать:

struct EditPrView: View {

    @Binding private var obj: A?
    @State private var count: Int

    init(obj: Binding<A?>) {
        self._obj = obj
        self.count = obj.wrappedValue is B ? 2 : 1
    }

    var body: some View {
        VStack {
            Text("foo-bar")
            Text(String(count))
        }
    }
}

Вы можете передать nameCount в родительском представлении, если не хотите использовать свой onAppear метод:

struct ParentView: View {
  var body: some View {
    EditPrView(
      name: name,
      nameCount: name.count
    )
  }
}

struct EditPrView: View {
    @State var name: String
    @State var nameCount: Int

    var body: some View {
        VStack {
            Text(name)
            Text(String(nameCount))
        }
    }
}

Обновлено: я бы также упомянул, что это не обязательно должно быть @Binding, если только вы не изменяете это значение nameCount изнутри EditPtrView, а затем используете это обновленное значение для чего-то еще в родительском представлении. То же самое и с @State: если вы не изменяете эти значения в представлении, это не обязательно должно быть @State. Вот как будет выглядеть пример привязки, если вы пытаетесь это сделать:

struct ParentView: View {
  @State var nameCount: Int = 0
  var body: some View {
    EditPrView(
      name: name,
      nameCount: $nameCount
    )
    .onAppear {
      nameCount = name.count
    }

  }
}

struct EditPrView: View {
    @State var name: String
    @Binding var nameCount: Int

    var body: some View {
        VStack {
            Text(name)
            Text(String(nameCount))
        }
    }
}

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