如何获得 UIAlertController observable(ReactiveCocoa 或 RxSwift)?
How to obtain a UIAlertController observable (ReactiveCocoa or RxSwift)?
我实现了 "reactive" 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
允许将所有代码保存在一个地方的解决方案是 extension
到 UIAlertViewController
:
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)
代码和逻辑非常简单,所以我在这里不给你解释。有问题就问。
我一直在寻找一种以响应方式使用 AlertController 的好方法,这个 post 帮助了我。
我使用了 Pacification 的解决方案,但我必须更新它才能 return 通用值而不是索引。我还将语法调整为 swift 4.
我post在这里,以防有人感兴趣。
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) }
}
}
}
此致
你可以使用这个UIAlert-RxSwift,
这是一个 Rx
扩展
我实现了 "reactive" 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
允许将所有代码保存在一个地方的解决方案是 extension
到 UIAlertViewController
:
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)
代码和逻辑非常简单,所以我在这里不给你解释。有问题就问。
我一直在寻找一种以响应方式使用 AlertController 的好方法,这个 post 帮助了我。
我使用了 Pacification 的解决方案,但我必须更新它才能 return 通用值而不是索引。我还将语法调整为 swift 4.
我post在这里,以防有人感兴趣。
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) }
}
}
}
此致
你可以使用这个UIAlert-RxSwift,
这是一个 Rx
扩展