Issue #104
I like extensions, and I like to group them under 1 common property to easily access. This also makes it clear that these all belong to the same feature and not to confuse with Apple properties.
Grouping all related extensions
This is how I do it in Anchor and On
activate(
a.anchor.top.left,
b.anchor.top.right,
c.anchor.bottom.left,
d.anchor.bottom.right
)
textField.on.text { text in
print("textField text has changed")
}
textField.on.didEndEditing { text in
print("texField has ended editing")
}
Generic extension
For On
, it is a bit tricky as it needs to adapt to different NSObject
subclasses. And to make auto completion work, meaning that each type of subclass gets its own function hint, we need to use generic and associatedtype
protocol.
You can take a look at Container and OnAware
public class Container<Host: AnyObject>: NSObject {
unowned let host: Host
init(host: Host) {
self.host = host
}
}
public protocol OnAware: class {
associatedtype OnAwareHostType: AnyObject
var on: Container<OnAwareHostType> { get }
}
RxCocoa
RxSwift has its RxCocoa
that does this trick too, so that you can just declare
button.rx.tap
textField.rx.text
alertAction.rx.isEnabled
The power lies in the struct Reactive and ReactiveCompatible
protocol
public struct Reactive<Base> {
/// Base object to extend.
public let base: Base
/// Creates extensions with base object.
///
/// - parameter base: Base object.
public init(_ base: Base) {
self.base = base
}
}
public protocol ReactiveCompatible {
/// Extended type
associatedtype CompatibleType
/// Reactive extensions.
static var rx: Reactive<CompatibleType>.Type { get set }
/// Reactive extensions.
var rx: Reactive<CompatibleType> { get set }
}
extension ReactiveCompatible {
/// Reactive extensions.
public static var rx: Reactive<Self>.Type {
get {
return Reactive<Self>.self
}
set {
// this enables using Reactive to "mutate" base type
}
}
/// Reactive extensions.
public var rx: Reactive<Self> {
get {
return Reactive(self)
}
set {
// this enables using Reactive to "mutate" base object
}
}
}
Here UIButton+Rx you can see how it can be applied to UIButton
extension Reactive where Base: UIButton {
/// Reactive wrapper for `TouchUpInside` control event.
public var tap: ControlEvent<Void> {
return controlEvent(.touchUpInside)
}
}