es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Propiedad publicada no se actualiza en SwiftUI

Tengo el siguiente código en el cual espero que las actualizaciones de la etiqueta de la propiedad “Published” se reflejen en la interfaz de usuario, pero no lo hace.

  public class ViewSearch {
    @ObservedObject var viewModel: ViewModel

  /// Inicializador principal para la instancia.
  /// - Parameter viewModel: El modelo de vista para la búsqueda.
  public init(viewModel: ViewModel) {
    self.viewModel = viewModel
  }

  func doSomething()  {
    for i in 1...1000000 {
      if i % 250000  == 0 {
        viewModel.label = "valor: \(i)"
      }
    }
    viewModel.label = "¡Hecho!"
  }
}

public class ViewModel: ObservableObject {
  @Published public var label = "valor inicial" {
    didSet {
      print("\(label)")
      self.objectWillChange.send()
    }
  }
  @Published public var searchText = ""

  var search: ViewSearch? = nil
}

struct ContentView: View {
  @ObservedObject var model: ViewModel

  var body: some View {
    TextField("Buscar", text: $model.searchText) { isEditing in
      if isEditing  {
        model.label = "valor inicial"
      }
    } onCommit: {
      if !model.searchText.isEmpty {
        model.search = ViewSearch(viewModel: model)
        model.search?.doSomething()
      }
    }

    Text(model.label)
  }
}

Las actualizaciones se activan al confirmar la entrada del campo de texto. Espero que la interfaz de usuario muestre “valor: 250000”, “valor: 500000”, etc. El observador didSet muestra el cambio, pero la interfaz de usuario no se actualiza. ¿Por qué no?

Tags:  ,

Answer

  1. Avatar for davy.ai

    Las actualizaciones no se reflejan en la interfaz de usuario (UI) porque el bucle for en la función doSomething() está bloqueando el hilo principal, lo que impide que se muestren las actualizaciones hasta que la función haya terminado. Para permitir que la interfaz de usuario se actualice durante el bucle, puedes utilizar DispatchQueue para ejecutar el bucle y actualizar la etiqueta en un hilo secundario (background thread), de la siguiente manera:

    func doSomething()  {
        DispatchQueue.global(qos: .background).async {
            for i in 1...1000000 {
                if i % 250000 == 0 {
                    DispatchQueue.main.async {
                        self.label = "valor: \(i)"
                    }
                }
            }
            DispatchQueue.main.async {
                self.label = "¡Hecho!"
            }
        }
    }
    

    Esto permitirá que la interfaz de usuario se actualice durante el bucle y muestre los nuevos valores de etiqueta a medida que se establecen.

Comments are closed.