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.

Swift se bloquea cuando se actualiza el valor publicado dentro de un hilo de forma sincrónica en iOS 13.

Tengo varios pasos que deben procesarse de forma sincrónica. Y el valor resultante del proceso es consumido por la vista. Funciona en iOS 14, pero se bloquea en iOS 13. Utilizo Combine para publicar un evento y actualizar el valor almacenado dentro del modelo de vista.

Este es el PublisherManager:

final class PublisherManager {
    static let shared = PublisherManager()
    private var cancellable = Set<anycancellable>()

    func mainPublisher() -> AnyPublisher<maininput, never=""> {
        mainSubject
            .eraseToAnyPublisher()
    }

    let mainSubject = PassthroughSubject<maininput, never="">()

    enum MainInput {
        case updateValue()
    }
}

Este es el modelo de vista:

final class ViewModel: ObservableObject {

    @Published var status: Status = .checking

    init() {
        setObserver()
        start()
    }

    private func setObserver() {
        PublisherManager.shared.mainPublisher()
            .receive(on: RunLoop.main)
            .sink { [weak self] action in
                guard let self = self else { return }
                switch action {
                case .updateValue:
                    self.updateValue()
                }
            }.store(in: &cancellable)
    }

    func start() {
        let dispatchGroup = DispatchGroup()
        let dispatchSemaphore = DispatchSemaphore(value: 1)

        dispatchGroup.enter()
        dispatchQueue.asyncAfter(deadline: DispatchTime.now() + 1) {
            dispatchSemaphore.wait()
            self.getValues { //--> Un proceso para llamar a una API
                PublisherManager.shared.pushNotificationTroubleshooterSubject.send(.updateValue())
                dispatchSemaphore.signal()
                dispatchGroup.leave()
            }
        }

        dispatchGroup.notify(queue: .main) {
            // Notificación
        }
    }

    private func updateValue() {
        status = .active
    }
}

Cuando lo ejecuto, obtengo un EXCBADACCESS en AppDelegate pero no muestra ningún error en el depurador. Si comento el código status = .active, no se bloquea.

¿Qué estoy haciendo mal y cómo puedo solucionar el problema?</maininput,></maininput,>

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    El problema puede estar relacionado con el acceso a la propiedad status desde diferentes hilos, ya que es probable que el método getValues sea llamado en un hilo de fondo. Una posible solución es utilizar DispatchQueue.main.async para actualizar la propiedad status en el hilo principal:

    private func updateValue() {
        DispatchQueue.main.async {
            self.status = .active
        }
    }
    

    Otro enfoque es utilizar una cola en serie para garantizar que el acceso a la propiedad status esté sincronizado entre hilos:

    private let statusQueue = DispatchQueue(label: "com.example.app.status", qos: .userInitiated)
    
    private func updateValue() {
        statusQueue.async {
            self.status = .active
        }
    }
    

    En cualquier caso, asegúrate de actualizar la propiedad status solo en el hilo principal para evitar problemas de seguridad de hilos.

Comments are closed.