Swift中的UIAlert不等待用户响应。

huangapple go评论76阅读模式
英文:

Swift UIAlert doesn't waiting user response

问题

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 let completionHandler = completionHandler {
        let okAction = UIAlertAction(title: "확인", style: .default) { _ in
            completionHandler()
        }
        alert.addAction(okAction)
    } else {
        let okAction = UIAlertAction(title: "확인", style: .default)
        alert.addAction(okAction)
    }
    if presentedViewController == nil {
        present(alert, animated: true, completion: nil)
    } else {
        presentedViewController?.dismiss(animated: false) {
            self.present(alert, animated: true, completion: nil)
        }
    }
}

请注意,我对 warningAlert 函数进行了一些更改,以确保在有其他弹出窗口时,先将其关闭再显示新的 UIAlertController。这应该有助于按照您希望的顺序显示 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)
}

I added UIAlert in ViewController but it doesn't wait user response and showing error.

I also tried await on self.present but not working too.
permissionInit has an await but it doesn't seem to work.

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.

I would like to show UIAlert in oder.

I would be grateful if you could let me know which part is wrong.

答案1

得分: 1

以下是翻译好的部分:

你正在调用三个函数,它们都试图同时(或几乎同时)显示警报。只有第一个成功,因为视图控制器只能呈现一个其他视图控制器。其他两个失败,这就是为什么你会收到两个错误消息的原因。

以下是一种将这三个请求连接起来的方法,以便每个请求都会等待前一个请求完成:

关键在于使用concat运算符,它只会一次订阅一个Observable。它会等待一个Observable停止后再订阅下一个Observable。

在这篇文章中了解更多信息:RxSwift中组合Observables的方法

最后,我也同意HangarRash的观点。

英文:

You are calling three functions, all of which try to present an alert at the same time (or nearly so.) Only the first one succeeds because a view controller can only present a single other view controller. The other two fail which is why you get the two error messages.

Here is one way to concatenate the three requests so that each one will wait until the previous ones are complete:

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()
}
}

The key is in using the concat operator which will only subscribe to one Observable at a time. It waits until an Observable stops before subscribing to the next one.

Learn more in this article: Recipes for Combining Observables in RxSwift

Lastly, I also agree with HangarRash.

huangapple
  • 本文由 发表于 2023年1月9日 13:57:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/75053636.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定