Swift UIAlert не ожидает ответа пользователя

func permissionInit() {
  Task{
        addListViewModel?.cameraPermission.accept(await chkCameraPermission())
            addListViewModel?.photoLibraryPermission.accept(await chkPhotoLibraryPermission())
            addListViewModel?.motionPermission.accept(await chkMotionPermission())
        }
    }

private func chkCameraPermission() async -> Bool{
        let mediaType = AVMediaType.video
        await AVCaptureDevice.requestAccess(for: mediaType)
        let mediaAuthoriztionStatus = AVCaptureDevice.authorizationStatus(for: mediaType)
        switch mediaAuthoriztionStatus{
        case .authorized:
            print("ShopUp Camera Permission True")
            return true
        case .denied, .restricted, .notDetermined:
            print("ShopUp Camera Permission False")
            warningAlert(title: "권한 오류", infoMativeMsg: "")
            return false
        default:
            return false
        }
    }
    
    private func chkPhotoLibraryPermission() async -> Bool {
        let status = await PHPhotoLibrary.requestAuthorization(for: .readWrite)
        switch status {
        case .authorized:
            print("ShopUp Photo Permission True")
            return true
        case .denied, .restricted, .notDetermined:
            print("ShopUp Photo Permission False")
            warningAlert(title: "권한 오류", infoMativeMsg: "")
            return false
        default:
            return false
        }
    }
    
    private func chkMotionPermission() async -> Bool{
        let coreMotionGranted = CMPedometer.authorizationStatus()
        switch coreMotionGranted {
        case .authorized:
            print("ShopUp CoreMotion Permission True")
            return true
        case .notDetermined, .restricted, .denied :
            print("ShopUp CoreMotion Permission False")
            warningAlert(title: "권한 오류", infoMativeMsg: "")
            return false
        default:
            return false
        }
    }
    
    func warningAlert(title: String, infoMativeMsg: String, completionHandler: Void? = nil) {
        let alert = UIAlertController(title: title, message: infoMativeMsg, preferredStyle: .alert)
        if completionHandler != nil {
            let okAction = UIAlertAction(title: "확인", style: .default, handler: {_ in completionHandler})
            alert.addAction(okAction)
        }else {
            let okAction = UIAlertAction(title: "확인", style: .default)
            alert.addAction(okAction)
        }
        self.present(alert, animated: true, completion: completionHandler != nil ? {completionHandler!} : nil)
    }

Я добавил UIAlert в ViewController, но он не ждет ответа пользователя и показывает ошибку.

Я также пробовал ждать на self.present, но тоже не работал. У разрешенияInit есть ожидание, но оно, похоже, не работает.

2023-01-09 14:45:37.015435+0900 ShopUp[544:94537] [Presentation] Attempt to present <UIAlertController: 0x12c03e000> on <UINavigationController: 0x12d019c00> (from <ShopUp.AddListViewController: 0x12ce08350>) while a presentation is in progress.
2023-01-09 14:45:37.015644+0900 ShopUp[544:94537] [Presentation] Attempt to present <UIAlertController: 0x12d07b800> on <UINavigationController: 0x12d019c00> (from <ShopUp.AddListViewController: 0x12ce08350>) while a presentation is in progress.

Я хотел бы показать UIAlert по порядку.

Я был бы признателен, если бы вы могли сообщить мне, какая часть неверна.

Что-то, что следует учитывать - это плохой пользовательский интерфейс, чтобы запросить кучу разрешений, подобных этому. Вы должны запрашивать разрешение только тогда, когда пользователь явно выполняет задачу, требующую данного разрешения. Например, не запрашивайте разрешение камеры, пока пользователь не решит сделать снимок с помощью камеры.

HangarRash 09.01.2023 07:39

Ошибка возникает из-за того, что ваши функции разрешений являются async, а warningAlert — нет, хотя они выполняют асинхронный код. Кстати, я согласен с HangarRash.

vadian 09.01.2023 08:56
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вы вызываете три функции, каждая из которых пытается представить предупреждение одновременно (или почти одновременно). Только первая из них завершается успешно, потому что контроллер представления может представить только один другой контроллер представления. Два других терпят неудачу, поэтому вы получаете два сообщения об ошибках.

Вот один из способов объединить три запроса, чтобы каждый ждал завершения предыдущих:

extension UIViewController {
    func permissionInit() {
        let avCapture = Observable.createAsync { await AVCaptureDevice.requestAccess(for: .video) }
            .filter { !$0 }
            .observe(on: MainScheduler.instance)
            .flatMap { [weak self] _ in self?.warningAlert(title: "권한 오류", infoMativeMsg: "") ?? Observable.empty() }

        let phPhoto = Observable.createAsync { await PHPhotoLibrary.requestAuthorization(for: .readWrite) }
            .filter { $0 != .authorized }
            .observe(on: MainScheduler.instance)
            .flatMap { [weak self] _ in self?.warningAlert(title: "권한 오류", infoMativeMsg: "") ?? Observable.empty() }

        let cmPedo = Observable.just(CMPedometer.authorizationStatus())
            .filter { $0 != .authorized }
            .flatMap { [weak self] _ in self?.warningAlert(title: "권한 오류", infoMativeMsg: "") ?? Observable.empty() }

        _ = Observable.concat(avCapture, phPhoto, cmPedo)
            .subscribe(onNext: {
                print("all requests complete.")
            })
    }

    func warningAlert(title: String, infoMativeMsg: String) -> Observable<Void> {
        Observable.deferred {
            let result = PublishSubject<Void>()
            let alert = UIAlertController(title: title, message: infoMativeMsg, preferredStyle: .alert)
            let okAction = UIAlertAction(title: "확인", style: .default, handler: { _ in result.onSuccess(()) })
            alert.addAction(okAction)
            self.present(alert, animated: true, completion: nil)
            return result
        }
    }
}

extension Observable {
    static func createAsync(_ asyncFunc: @escaping () async throws -> Element) -> Observable<Element> {
        Observable.create { observer in
            let task = Task {
                do {
                    observer.onSuccess(try await asyncFunc())
                } catch {
                    observer.onError(error)
                }
            }
            return Disposables.create { task.cancel() }
        }
    }
}

public extension ObserverType {
    func onSuccess(_ element: Element) -> Void {
        onNext(element)
        onCompleted()
    }
}

Суть в использовании оператора concat, который будет подписываться только на один Observable за раз. Он ждет, пока Observable остановится, прежде чем подписаться на следующий.

Узнайте больше в этой статье: Рецепты объединения Observables в RxSwift

Наконец, я также согласен с HangarRash.

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