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 по порядку.
Я был бы признателен, если бы вы могли сообщить мне, какая часть неверна.
Ошибка возникает из-за того, что ваши функции разрешений являются async
, а warningAlert
— нет, хотя они выполняют асинхронный код. Кстати, я согласен с HangarRash.
Вы вызываете три функции, каждая из которых пытается представить предупреждение одновременно (или почти одновременно). Только первая из них завершается успешно, потому что контроллер представления может представить только один другой контроллер представления. Два других терпят неудачу, поэтому вы получаете два сообщения об ошибках.
Вот один из способов объединить три запроса, чтобы каждый ждал завершения предыдущих:
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.
Что-то, что следует учитывать - это плохой пользовательский интерфейс, чтобы запросить кучу разрешений, подобных этому. Вы должны запрашивать разрешение только тогда, когда пользователь явно выполняет задачу, требующую данного разрешения. Например, не запрашивайте разрешение камеры, пока пользователь не решит сделать снимок с помощью камеры.