Просмотр не обновляется при изменении переменной среды

#ios #swift #swiftui

#iOS #swift #swiftui

Вопрос:

Я пытаюсь использовать переменную глобальной среды в качестве статуса, чтобы проверить, должно ли приложение отображать экран загрузки (блокировка пользовательского интерфейса и предотвращение касаний)

Я не использую @EnvironmentObject , потому что у меня может быть несколько объектов для разных уведомлений

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

 import SwiftUI

@main
struct TestApp: App {
    var body: some Scene {
      WindowGroup {
        NewView()
          .environment(.counter, GlobalCounter(start: 5))
      }
    }
}

struct NewView: View {
  @Environment(.counter) var counter: GlobalCounter
  
  var body: some View {
    Text("COUNT: (counter.value)")
    Button("UP") {
      counter.increment()
    }
  }
}

struct GlobalCounterKey: EnvironmentKey {
    static public let defaultValue: GlobalCounter = GlobalCounter(start: 1)
}

extension EnvironmentValues {
  var counter: GlobalCounter {
    get {
      return self[GlobalCounterKey.self]
    }
    set {
      self[GlobalCounterKey.self] = newValue
    }
  }
}

class GlobalCounter: ObservableObject {
  @Published var value: Int = 0
  
  init(start: Int = 0) {
    self.value = start
  }
  
  func increment() {
    value  = 1
  }
}
 

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

Что я делаю не так?

Комментарии:

1. Среда здесь не является подходящим инструментом — она не наблюдает за наблюдаемыми объектами. Вам необходимо ввести свой счетчик как ObservedObject.

2. Хорошо, тогда как я могу сделать его наблюдаемым? Мне нужно передать эту переменную нескольким дочерним представлениям. И диспетчер данных обновит его асинхронным методом. Как я могу заставить его обновлять представления?

3. @Asperi это неверно, согласно документации : «Если значение изменяется, SwiftUI обновляет любые части вашего представления, которые зависят от значения». Вы не можете напрямую изменять его значения, но вы можете вызывать методы изменения, которые, в моем случае, не запускают просмотры для обновления

4. Да, документация верна, но ваш GlobalCounter не является значением, это ссылка, и она не изменяется, измененное свойство ссылается где-то в памяти, но оно никак не связано со значением среды.

5. функция func increment() не является мутирующим методом. Если вы измените GlobalCounter на struct и добавите к нему «mutating», это так.

Ответ №1:

Используйте EnvironmentObject вместо этого.

 @main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
              .environmentObject(GlobalCounter(start: 5))
        }
    }
}



struct ContentView: View {
    var body: some View {
        NavigationView {
           NewView()
        }
    }
}



struct NewView: View {
  @EnvironmentObject var counter: GlobalCounter
  
  var body: some View {
    VStack{
        Text("COUNT: (counter.value)")
        Button("UP") {
          counter.increment()
        }
    }
  }
}


struct GlobalCounterKey: EnvironmentKey {
    static public let defaultValue: GlobalCounter = GlobalCounter(start: 1)
}

extension EnvironmentValues {
  var counter: GlobalCounter {
    get {
      return self[GlobalCounterKey.self]
    }
    set {
      self[GlobalCounterKey.self] = newValue
    }
  }
}

class GlobalCounter: ObservableObject {
  @Published var value: Int = 0
  
  init(start: Int = 0) {
    self.value = start
  }
  
  func increment() {
    value  = 1
  }
}
 

Комментарии:

1. Как я уже говорил в вопросе, я стараюсь избегать EnvironmentObject , потому что хочу использовать несколько объектов. И использование environment(_:_:) было бы лучшим для нас, потому что мы можем сказать, какая переменная получит какую переменную

2. @NicosKaralis Можете ли вы дать больше информации в своем вопросе? Вы можете установить новый EnvironmentObject для дочерних элементов, если хотите использовать разные объекты, поэтому мне трудно понять, зачем вам EnvironmentValue