AlertReactor is a ReactorKit extension for UIAlertController. It provides an elegant way to deal with an UIAlertController. Best fits if you have lazy-loaded alert actions.
- ✏️ Statically typed alert actions
- 🕹 Reactive and dynamic action bindings
This is an example implementation of an AlertReactor
:
final class UserAlertReactor: AlertReactor<UserAlertAction> {
override func mutate(action: Action) -> Observable<Mutation> {
switch action {
case .prepare:
return .just(.setActions([.copy, .follow, .block, .cancel]))
case let .selectAction(alertAction):
switch alertAction {
case .copy: return foo()
case .follow: return foo()
case .unfollow: return foo()
case .block: return foo()
case .cancel: return foo()
}
}
}
}
First you should define a new type which conforms to a protocol AlertActionType
. This is an abstraction model of UIAlertAction
. This protocol requires a title
(required), style
(optional) and isEnabled
(optional) property.
enum UserAlertAction: AlertActionType {
case loading
case follow
case block
case cancel
// required
var title: String {
switch self {
case .loading: return "Loading"
case .follow: return "Follow"
case .block: return "Block"
case .cancel: return "Cancel"
}
}
// optional
var style: UIAlertActionStyle {
switch self {
case .loading: return .default
case .follow: return .default
case .block: return .destructive
case .cancel: return .cancel
}
}
// optional
var isEnabled: Bool {
switch self {
case .loading: return false
default: return true
}
}
}
AlertReactor
is a generic reactor class. It takes a single generic type which conforms to a protocol AlertActionType
. This reactor provides a default action, mutation and a state. Here is a simplified definition of AlertReactor
. You may subclass this class and override mutate(action:)
method to implement specific business logic.
class AlertReactor<AlertAction: AlertActionType>: Reactor {
enum Action {
case prepare // on viewDidLoad()
case selectAction(AlertAction) // on select action
}
enum Mutation {
case setTitle(String?)
case setMessage(String?)
case setActions([AlertAction])
}
struct State {
public var title: String?
public var message: String?
public var actions: [AlertAction]
}
}
We're gonna use the UserAlertAction
as a generic parameter to create a new subclass of AlertReactor
.
final class UserAlertReactor: AlertReactor<UserAlertAction> {
override func mutate(action: Action) -> Observable<Mutation> {
switch action {
case .prepare:
return .just(Mutation.setActions([.copy, .follow, .block, .cancel]))
case let .selectAction(alertAction):
switch alertAction {
case .loading: return .empty()
case .follow: return UserAPI.follow()
case .block: return UserAPI.block()
case .cancel: return .empty()
}
}
}
}
AlertController
is a subclass of UIAlertController
which conforms to a protocol View
from ReactorKit. This class also takes a single generic type of AlertActionType
. You can initialize this class with some optional parameters: reactor
and preferredStyle
. Just present it then the reactor will handle the business logic for you.
let reactor = UserAlertReactor()
let controller = AlertController<UserAlertAction>(reactor: reactor, preferredStyle: .actionSheet)
self.present(controller, animated: true, completion: nil)
pod 'AlertReactor'
AlertReactor is under MIT license. See the LICENSE for more info.