如何执行推送UIViewController或存在的UIAlertController?

时间:2019-05-27 02:08:14

标签: swift mvvm uiviewcontroller uialertcontroller rx-swift

在调用了一些API之后,我进行了检查,以导航到另一个屏幕或在同一屏幕上显示警报。当前,我通过创建一个返回 UIViewController 类型的可观察对象来实现此目的,但是推送UIAlertController会导致问题。

关于应该如何做的任何建议/想法?

ViewModel.swift

struct Book: Decodable {
   let feed: Feed
   let entry: [Entry] 
   init (from decoder :Decoder) throws {
     let container = try decoder.container(keyedBy: CodingKeys.self)
      do {
        value = try container.decode([Entry].self, forKey: .value)
      } catch {
        let newValue = try container.decode(Entry.self, forKey: .value)
        value = [newValue]
      }
   }
}

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

3 个答案:

答案 0 :(得分:0)

您可以使用 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)

答案 1 :(得分:0)

有一些选择。

第一个选择是采用当前的实现。 您可以在nextAction的onNext事件中传递ViewView之外的信息,这将告诉您如何显示VC。

例如,您可以创建一个关联的枚举

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

并像这样重复使用它:

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)

第二个选项(在某种意义上更灵活和可测试)是创建一个单独的Router类,该类负责创建和显示下一个屏幕(具有功能showLoginshowAlert等)。可以将路由器直接注入ViewModel中,您可以调用路由器在例如可观察对象的do(onNext)事件中显示下一个屏幕。

答案 2 :(得分:0)

您可以查看is关键字,该关键字使您可以检查对象类型。 More on is keyword。一种替代方法是使用type(of: object)并与UIAlertViewController.self

进行比较

由于您必须提供一个UIAlertViewController而不是将其推送,因此如果type为UIAlertViewController,请使用if和else与上面的内容一起呈现,否则请推送。注意:因为它们全部都是,所以不必检查UIViewController。