【问题标题】:How to obtain a UIAlertController observable (ReactiveCocoa or RxSwift)?如何获取 UIAlertController 可观察对象(ReactiveCocoa 或 RxSwift)?
【发布时间】:2018-09-07 09:03:12
【问题描述】:

我实现了一个“反应式”UIAlertController,所以我可以得到一个按下按钮的Observable<Int>。 (见下面的代码)。

我的一个或多个问题是:

  • 这个实现是否正确?我不喜欢存储观察者;我想知道是否有更好的解决方案。
  • 或者...是否已经在 ReactiveCocoa 或 RxSwift 中实现了此功能?

这里是实现。我删除了与问题无关的部分。

class AlertBuilder {

    typealias AlertAction = (Int) -> ()

    private let alert: UIAlertController

    /** If observable() is called, we keep here the observers to notify them */
    private var observers: [AnyObserver<Int>] = []

    init(alert: UIAlertController) {
        self.alert = alert
    }

    /** When using observable(), the action is not needed. */
    func button(_ title: String, style: UIAlertActionStyle = .default, action: AlertAction? = nil) -> AlertBuilder {

        let buttonIndex = alert.actions.count
        alert.addAction( UIAlertAction(title: title, style: style, handler: { [weak self] _ in

            // Callback via action
            action?(buttonIndex)

            // Callback via observers
            if let this = self {
                for observer in this.observers {
                    observer.onNext(buttonIndex)
                    observer.onCompleted()
                }
                this.observers = []
            }
        }) )
        return self
    }

    /**
     * Returns an Observable that will emit the pressed button index and complete.
     * It's important to keep a reference to the AlertBuilder, otherwise the events won't be received.
     */
    func observable() -> Observable<Int> {

        return Observable<Int>.create { observer in
            self.observers.append(observer)
            return Disposables.create()
        }
    }
}

您可以从控制器中使用它,如下所示:

let alert = UIAlertController(title: "title", message: "msg", preferredStyle: .actionSheet)

let builder = AlertBuilder(alert: alert)
    .button("no", style: .destructive)
    .button("yes")

self.present(alert, animated: true, completion: nil)

self.builder.observable()
    .subscribe(onNext: { buttonIndex in /* ... */ })
    .disposed(by: bag)

// keep reference to builder so observable() works
self.builder = builder

【问题讨论】:

    标签: ios reactive-cocoa rx-swift


    【解决方案1】:

    你可以使用这个UIAlert-RxSwift, 这是一个Rx 扩展

    【讨论】:

      【解决方案2】:

      我正在寻找一种以响应式方式使用 AlertController 的好方法,这篇文章对我有帮助。

      我使用了 Pacification 的解决方案,但我必须对其进行更新才能返回通用值而不是索引。我还调整了 swift 4 的语法。

      我把它贴在这里以防有人感兴趣。

      extension UIAlertController {
        struct Action<T> {
          var title: String?
          var style: UIAlertAction.Style
          var value: T
      
          static func action(title: String?, style: UIAlertAction.Style = .default, value: T) -> Action {
            return Action(title: title, style: style, value: value)
          }
        }
      
        static func present<T>(in viewController: UIViewController,
                            title: String? = nil,
                            message: String? = nil,
                            style: UIAlertController.Style,
                            actions: [Action<T>]) -> Observable<T> {
          return Observable.create { observer in
            let alertController = UIAlertController(title: title, message: message, preferredStyle: style)
      
            actions.enumerated().forEach { index, action in
              let action = UIAlertAction(title: action.title, style: action.style) { _ in
                observer.onNext(action.value)
                observer.onCompleted()
              }
              alertController.addAction(action)
            }
      
            viewController.present(alertController, animated: true, completion: nil)
            return Disposables.create { alertController.dismiss(animated: true, completion: nil) }
          }
        }
      }
      

      问候

      【讨论】:

        【解决方案3】:

        允许将所有代码保存在一个位置的解决方案是extensionUIAlertViewController

        extension UIAlertController {
        
            struct AlertAction {
                var title: String?
                var style: UIAlertActionStyle
        
                static func action(title: String?, style: UIAlertActionStyle = .default) -> AlertAction {
                    return AlertAction(title: title, style: style)
                }
            }
        
            static func present(
                in viewController: UIViewController,
                title: String?, 
                message: String?,
                style: UIAlertControllerStyle,
                actions: [AlertAction])
                -> Observable<Int>
            {
                return Observable.create { observer in
                    let alertController = UIAlertController(title: title, message: message, preferredStyle: style)
        
                    actions.enumerated().forEach { index, action in
                        let action = UIAlertAction(title: action.title, style: action.style) { _ in
                            observer.onNext(index)
                            observer.onCompleted()
                        }
                        alertController.addAction(action)
                    }
        
                    viewController.present(alertController, animated: true, completion: nil)
                    return Disposables.create { alertController.dismiss(animated: true, completion: nil) }
                }
        
            }
        
        }
        

        及用法:

        let actions: [UIAlertController.AlertAction] = [
            .action(title: "no", style: .destructive),
            .action(title: "yes")
        ]
        
        UIAlertController
            .present(in: self, title: "Alert", message: "message", style: .alert, actions: actions)
            .subscribe(onNext: { buttonIndex in
                print(buttonIndex)
            })
            .disposed(by: bag)
        

        代码和逻辑非常简单,所以我在这里不做解释。如果您有任何问题,请询问。

        【讨论】:

        • 谢谢,很好的解决方案!我看到您在Observable.create 中创建了UIAlertAction 回调,因此您可以在那里使用观察者。我没想到。另外,我没想到在 dispose 上调用dismiss
        • 非常干净和简单的解决方案。
        猜你喜欢
        • 2018-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多