简体   繁体   English

如何执行push UIViewController或UIAlertController的礼物?

[英]How do I perform either a push UIViewController or a present of UIAlertController?

After some API calls, I have a check to either navigate to another screen or show an alert on the same screen. 在一些API调用之后,我会检查导航到另一个屏幕或在同一屏幕上显示警报。 Currently, I am doing this by creating an observable that returns a UIViewController type but pushing a UIAlertController causes problem. 目前,我通过创建一个返回UIViewController类型的observable来执行此操作,但是推送UIAlertController会导致问题。

Any suggestions/ideas on how this should be done? 关于如何做到这一点的任何建议/想法?

ViewModel.swift ViewModel.swift

let nextAction = Observable.combineLatest(appVersionOutput, serviceAvailabilityOutput, getLanguagePackOutput,
                                              resultSelector:
        { appVersion, _, _ -> UIViewController in
            if appVersion.currentAppVersion == "1.0.0" {
                let appServiceAvailability = Availability.shared.getAppStatus()
                if appServiceAvailability {
                    return LoginLandingViewController()
                } else {
                    return ServiceMaintenanceViewController()
                }
            } else {
                return UIAlertController()
            }
        })

ViewController.swift ViewController.swift

viewModel.output.nextAction
        .subscribe(onNext: { [weak self] screen in
            self?.navigationController?.pushViewController(screen, animated: true) 
        }) // PROBLEM FACED: Pushing a UIAlertController
        .disposed(by: disposeBag)

You can check the class using classForCoder 您可以使用classForCoder检查类

viewModel.output.nextAction
    .subscribe(onNext: { [weak self] screen in
        if String(describing: screen.classForCoder) == "UIAlertController" {
            //present
            self?.present(screen, animated: true, completion: nil)
        } else {
            //navigate
            self?.navigationController?.pushViewController(screen, animated: true)
        } 
    }) // PROBLEM FACED: Pushing a UIAlertController
    .disposed(by: disposeBag)

There're a few options. 有几个选择。

The first option is the adoption of your current implementation. 第一种选择是采用您当前的实现。 You could pass an information in addition to ViewController in onNext event of nextAction observable, that will tell how to show the VC. 您可以在nextAction observable的onNext事件中传递除ViewController之外的信息,这将告诉您如何显示VC。

For instance, you can create an associated enum 例如,您可以创建关联的枚举

// you can call it NextAction, Action etc
enum PresentationType {
    case
    push(UIViewController),
    present(UIViewController)
}

and reuse it like this: 并重复使用它:

let nextAction = Observable.combineLatest(appVersionOutput, serviceAvailabilityOutput, getLanguagePackOutput,
                                          resultSelector:
    { appVersion, _, _ -> PresentationType in
        if appVersion.currentAppVersion == "1.0.0" {
            let appServiceAvailability = Availability.shared.getAppStatus()
            if appServiceAvailability {
                return .push(LoginLandingViewController())
            } else {
                return .push(ServiceMaintenanceViewController()) // use .present if should present modally
            }
        } else {
            return .present(UIAlertController())
        }
})

// somewhere in viewController

viewModel.output.nextAction
        .subscribe(onNext: { [weak self] action in
        switch action {
            case .push(let vc):
                self?.navigationController?.pushViewController(vc, animated: true)
            case .present(let vc):
                self?.present(vc, animated: true, completion: nil)

        })
        .disposed(by: disposeBag)

The second (and more flexible and testable in some sense) option would be to create a separate Router class which is responsible for creating and showing next screens (with functions showLogin , showAlert etc). 第二个(在某种意义上更灵活和可测试)选项是创建一个单独的Router类,负责创建和显示下一个屏幕(使用showLoginshowAlert等函数)。 The router can be directly injected in ViewModel and you can call the Router to show next screens in, for example, do(onNext) events in your observables. 路由器可以直接注入ViewModel,您可以调用路由器以显示下一个屏幕,例如,您的observable中的do(onNext)事件。

You can look at the is keyword which allows you to check the object type. 您可以查看is关键字,它允许您检查对象类型。 More on is keyword . 更多关于关键字 An alternative will be to use type(of: object) and compare to UIAlertViewController.self 另一种方法是使用type(of: object)并与UIAlertViewController.self进行比较

Since you have to present a UIAlertViewController and not push it, use if and else with the above to present if type is UIAlertViewController and push if otherwise. 因为您必须呈现UIAlertViewController而不是推送它,所以如果type是UIAlertViewController则使用if和else以及上面的内容,否则将推送。 NB: Unnecessary to check for UIViewController since they all are. 注意:不必检查UIViewController,因为它们都是。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 SwiftUI 中显示 UIAlertController? - How do I present a UIAlertController in SwiftUI? 如何呈现位于另一个UIViewController中的UIAlertController - how to present UIAlertController located in another UIViewController 在当前活动的UIViewController中呈现UIAlertController - Present UIAlertController in the currently active UIViewController 使用Storyboard Refrences时如何显示新的UIViewController - How do I present a new UIViewController when Storyboard Refrences are used 如何使用 UIAlertController 显示警报 - How to present an alert with UIAlertController ios - 如何在iOS Swift 3中以编程方式推送和呈现给UIViewController而无需segue - How to push and present to UIViewController programmatically without segue in iOS Swift 3 如何以编程方式从 iOS Swift 3 - How to push and present to UIViewController programmatically From a XIB in iOS Swift 3 尝试在已经呈现UIAlertController的ViewController上呈现UIViewController - Attempt to present UIViewController on ViewController which is already presenting UIAlertController iOS版。尝试在UIViewController上呈现UIAlertController,其视图不在窗口层次结构中 - iOS. Attempt to present UIAlertController on UIViewController whose view is not in the window hierarchy 如何从视图中呈现UIAlertController? - How to present a UIAlertController from a view?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM