Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ env:

git:
submodules: false
before_install:
- curl -OlL "https://github.com/Carthage/Carthage/releases/download/0.11/Carthage.pkg"
- sudo installer -pkg "Carthage.pkg" -target /
- rm "Carthage.pkg"

script:
- set -o pipefail
Expand All @@ -25,3 +21,15 @@ script:

notifications:
email: false
before_deploy:
- carthage build --no-skip-current
- carthage archive Rex
deploy:
provider: releases
api_key:
secure: lNuRUOxMrw2YSsibAAK+8GH35KfvgheiyBGsqD7Rqwjzf3orhTmNbWeRt38YiUxzmNZSzhQdcglwJnw9ymXuGyynOwWxRPbQnX0KE+fTIyoyZrxIwxkqyU6aGzgi1bGa/URKU83pDZsBrfPeLa89w5PYZ8UVPVs+alD796WTjNoXFhxvj4cZtT65Pqk4usSgq3l6GRGzVDmaOgiiDT509LdTi+x+BjRuQcP2wvxCKWGWtaR4COo+PH96mQ/vcykL97zyxScWOBRbVq5YEeqHC/OHV7kXMLRK6X0SBcpB8otV9ObxN76zqZjpxQ59/g0WN4bUogd5VYT11dxjSAQDNAtS/H0iHcw6ojDuAobQbD1W4Um6tHBPaT4ZVXDack8J2gSa2DhiFBt198XRSEWFczff5LevxFJaDwqLwEj5qtB6bkdvarsaZdlUzaPfmBfEjmLQdQmiEe82xYb+VcZK0SlgbNulvSt8J2FpLRcVQSs7Ef75zMKQECtxJCsOhSFGT+1Zal2YEk70HFdbkNE0DS57AX0hmgDFF0WhK1ZzpBgy432Hyo71srAJMyalMfF1zuc5kHSssezQ30p7ZdegDnkvbt0lhjGFgUlbKIoLS9e21uo3i96XZQagL5k/mZPxaq1hf1bsH+ow+Jcg3X7b8RJRqniHxASyffdzHYbmfyE=
file: Rex.framework.zip
skip_cleanup: true
on:
repo: RACCommunity/Rex
tags: true
2 changes: 1 addition & 1 deletion Cartfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
github "ReactiveCocoa/ReactiveCocoa" ~> 4.1
github "ReactiveCocoa/ReactiveCocoa" ~> 4.2.1
4 changes: 2 additions & 2 deletions Cartfile.resolved
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
github "antitypical/Result" "2.0.0"
github "ReactiveCocoa/ReactiveCocoa" "v4.1.0"
github "antitypical/Result" "2.1.1"
github "ReactiveCocoa/ReactiveCocoa" "v4.2.1"
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Rex [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
Extensions for [ReactiveCocoa](https://github.com/ReactiveCocoa/ReactiveCocoa) that may not fit in the core framework.

New development targets RAC 4/Swift 2/Xcode 7. For RAC 3 support [see the 0.5 release](https://github.com/neilpa/Rex/releases/tag/v0.5.0).
New development targets RAC 4/Swift 2/Xcode 7. For RAC 3 support [see the 0.5
release](https://github.com/RACCommunity/Rex/releases/tag/v0.5.0).

## Signal
All `Signal` operators are available for `SignaProducer`s too via explicit `lift`ing.
Expand Down Expand Up @@ -54,7 +55,7 @@ Flexible way to bind `CocoaAction` to the press of button. In addition the butto

```swift
let downloadAction = Action<UIButton, NSData, NSError> { _ in
let url = NSURL(string: "https://github.com/neilpa/Rex/archive/master.zip")
let url = NSURL(string: "https://github.com/RACCommunity/Rex/archive/master.zip")
let request = NSURLRequest(URL: url!)
return NSURLSession.sharedSession().rac_dataWithRequest(request).map { $0.0 }
}
Expand Down
2 changes: 1 addition & 1 deletion Rex.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Pod::Spec.new do |s|

s.source_files = 'Source/**/*.swift'
s.ios.exclude_files = 'Source/AppKit/*'
s.tvos.exclude_files = 'Source/AppKit/*', 'Source/UIKit/UIDatePicker.swift', 'Source/UIKit/UISwitch.swift'
s.tvos.exclude_files = 'Source/AppKit/*', 'Source/UIKit/UIDatePicker.swift', 'Source/UIKit/UISwitch.swift', 'Source/UIKit/UISegmentedControl.swift'
s.watchos.exclude_files = 'Source/AppKit/*', 'Source/UIKit/*'
s.osx.exclude_files = 'Source/UIKit/*'

Expand Down
94 changes: 70 additions & 24 deletions Rex.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Source/Foundation/Association.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,12 @@ public func associatedProperty<T: AnyObject>(host: AnyObject, keyPath: StaticStr
/// This can be used as an alternative to `DynamicProperty` for creating strongly typed
/// bindings on Cocoa objects.
@warn_unused_result(message="Did you forget to use the property?")
public func associatedProperty<Host: AnyObject, T>(host: Host, key: UnsafePointer<()>, @noescape initial: Host -> T, setter: (Host, T) -> ()) -> MutableProperty<T> {
public func associatedProperty<Host: AnyObject, T>(host: Host, key: UnsafePointer<()>, @noescape initial: Host -> T, setter: (Host, T) -> (), @noescape setUp: MutableProperty<T> -> () = { _ in }) -> MutableProperty<T> {
return associatedObject(host, key: key) { host in
let property = MutableProperty(initial(host))

setUp(property)

property.producer.startWithNext { [weak host] next in
if let host = host {
setter(host, next)
Expand Down
17 changes: 1 addition & 16 deletions Source/Signal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,7 @@ extension SignalType {
return disposable
}
}

/// Enforces that at least `interval` time passes before forwarding a value. If a
/// new value arrives, the previous one is dropped and the `interval` delay starts
/// again. Error events are immediately forwarded, even if there's a queued value.
///
/// This operator is useful for scenarios like type-to-search where you want to
/// wait for a "lull" in typing before kicking off a search request.
@warn_unused_result(message="Did you forget to call `observe` on the signal?")
public func debounce(interval: NSTimeInterval, onScheduler scheduler: DateSchedulerType) -> Signal<Value, Error> {
precondition(interval >= 0)

return flatMap(.Latest) {
SignalProducer(value: $0).delay(interval, onScheduler: scheduler)
}
}


/// Forwards a value and then mutes the signal by dropping all subsequent values
/// for `interval` seconds. Once time elapses the next new value will be forwarded
/// and repeat the muting process. Error events are immediately forwarded even while
Expand Down
11 changes: 0 additions & 11 deletions Source/SignalProducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,6 @@ extension SignalProducerType {
return lift { $0.timeoutAfter(interval, withEvent: event, onScheduler: scheduler) }
}

/// Enforces that at least `interval` time passes before forwarding a value. If a
/// new value arrives, the previous one is dropped and the `interval` delay starts
/// again. Error events are immediately forwarded, even if there's a queued value.
///
/// This operator is useful for scenarios like type-to-search where you want to
/// wait for a "lull" in typing before kicking off a search request.
@warn_unused_result(message="Did you forget to call `start` on the producer?")
public func debounce(interval: NSTimeInterval, onScheduler scheduler: DateSchedulerType) -> SignalProducer<Value, Error> {
return lift { $0.debounce(interval, onScheduler: scheduler) }
}

/// Forwards a value and then mutes the producer by dropping all subsequent values
/// for `interval` seconds. Once time elapses the next new value will be forwarded
/// and repeat the muting process. Error events are immediately forwarded even while
Expand Down
29 changes: 29 additions & 0 deletions Source/UIKit/UIActivityIndicatorView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// UIActivityIndicatorView.swift
// Rex
//
// Created by Evgeny Kazakov on 02/07/16.
// Copyright © 2016 Neil Pankey. All rights reserved.
//

import ReactiveCocoa
import UIKit

extension UIActivityIndicatorView {

/// Wraps an indicator's `isAnimating()` state in a bindable property.
/// Setting a new value to the property would call `startAnimating()` or
/// `stopAnimating()` depending on the value.
public var rex_animating: MutableProperty<Bool> {
return associatedProperty(self, key: &animatingKey, initial: { $0.isAnimating() }, setter: { host, animating in
if animating {
host.startAnimating()
} else {
host.stopAnimating()
}
})
}

}

private var animatingKey: UInt8 = 0
17 changes: 17 additions & 0 deletions Source/UIKit/UIControl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import UIKit
import enum Result.NoError

extension UIControl {

#if os(iOS)
/// Creates a producer for the sender whenever a specified control event is triggered.
@warn_unused_result(message="Did you forget to use the property?")
Expand All @@ -20,6 +21,21 @@ extension UIControl {
.map { $0 as? UIControl }
.flatMapError { _ in SignalProducer(value: nil) }
}

/// Creates a bindable property to wrap a control's value.
///
/// This property uses `UIControlEvents.ValueChanged` and `UIControlEvents.EditingChanged`
/// events to detect changes and keep the value up-to-date.
//
@warn_unused_result(message="Did you forget to use the property?")
class func rex_value<Host: UIControl, T>(host: Host, getter: Host -> T, setter: (Host, T) -> ()) -> MutableProperty<T> {
return associatedProperty(host, key: &valueChangedKey, initial: getter, setter: setter) { property in
property <~
host.rex_controlEvents([.ValueChanged, .EditingChanged])
.filterMap { $0 as? Host }
.filterMap(getter)
}
}
#endif

/// Wraps a control's `enabled` state in a bindable property.
Expand All @@ -41,3 +57,4 @@ extension UIControl {
private var enabledKey: UInt8 = 0
private var selectedKey: UInt8 = 0
private var highlightedKey: UInt8 = 0
private var valueChangedKey: UInt8 = 0
20 changes: 5 additions & 15 deletions Source/UIKit/UIDatePicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,14 @@
// Created by Guido Marucci Blas on 3/25/16.
// Copyright © 2016 Neil Pankey. All rights reserved.
//
import UIKit

import ReactiveCocoa
import UIKit

extension UIDatePicker {


// Wraps a datePicker's `date` value in a bindable property.
public var rex_date: MutableProperty<NSDate> {
let initial = { (picker: UIDatePicker) -> NSDate in
picker.addTarget(self, action: #selector(UIDatePicker.rex_changedDate), forControlEvents: .ValueChanged)
return picker.date
}
return associatedProperty(self, key: &dateKey, initial: initial) { $0.date = $1 }
}

@objc
private func rex_changedDate() {
rex_date.value = date
return UIControl.rex_value(self, getter: { $0.date }, setter: { $0.date = $1 })
}

}

private var dateKey: UInt8 = 0
43 changes: 43 additions & 0 deletions Source/UIKit/UIGestureRecognizer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// UIGestureRecognizer.swift
// Rex
//
// Created by Siemen Sikkema on 25/05/16.
// Copyright © 2016 Neil Pankey. All rights reserved.
//

import ReactiveCocoa
import UIKit

extension UIGestureRecognizer {

/// Wraps a gesture recognizer's `enabled` state in a bindable property.
public var rex_enabled: MutableProperty<Bool> {
return associatedProperty(self, key: &enabledKey, initial: { $0.enabled }, setter: { $0.enabled = $1 })
}

/// Exposes a property that binds an action to gesture events. The action is set as
/// a target of the gesture recognizer. When property changes occur the
/// previous action is removed as a target. This also binds the enabled state of the
/// action to the `rex_enabled` property on the button.
public var rex_action: MutableProperty<CocoaAction> {
return associatedObject(self, key: &actionKey) { host in
let initial = CocoaAction.rex_disabled
let property = MutableProperty(initial)

property.producer
.combinePrevious(initial)
.startWithNext { [weak host] previous, next in
host?.removeTarget(previous, action: CocoaAction.selector)
host?.addTarget(next, action: CocoaAction.selector)
}

host.rex_enabled <~ property.producer.flatMap(.Latest) { $0.rex_enabledProducer }

return property
}
}
}

private var actionKey: UInt8 = 0
private var enabledKey: UInt8 = 0
5 changes: 3 additions & 2 deletions Source/UIKit/UILabel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import UIKit

extension UILabel {
/// Wraps a label's `text` value in a bindable property.
public var rex_text: MutableProperty<String> {
return associatedProperty(self, keyPath: "text")
public var rex_text: MutableProperty<String?> {
return associatedProperty(self, key: &attributedTextKey, initial: { $0.text }, setter: { $0.text = $1 })
}

/// Wraps a label's `attributedText` value in a bindable property.
Expand All @@ -26,5 +26,6 @@ extension UILabel {
}
}

private var textKey: UInt8 = 0
private var attributedTextKey: UInt8 = 0
private var textColorKey: UInt8 = 0
22 changes: 22 additions & 0 deletions Source/UIKit/UISegmentedControl.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// UISegmentedControl.swift
// Rex
//
// Created by Markus Chmelar on 07/06/16.
// Copyright © 2016 Neil Pankey. All rights reserved.
//

import ReactiveCocoa
import UIKit

extension UISegmentedControl {
/// Wraps a segmentedControls `selectedSegmentIndex` state in a bindable property.
public var rex_selectedSegmentIndex: MutableProperty<Int> {
let property = associatedProperty(self, key: &selectedSegmentIndexKey, initial: { $0.selectedSegmentIndex }, setter: { $0.selectedSegmentIndex = $1 })
property <~ rex_controlEvents(.ValueChanged)
.filterMap { ($0 as? UISegmentedControl)?.selectedSegmentIndex }
return property
}
}

private var selectedSegmentIndexKey: UInt8 = 0
13 changes: 2 additions & 11 deletions Source/UIKit/UISwitch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,8 @@ import UIKit

extension UISwitch {

/// Wraps a switch's `on` state in a bindable property.
/// Wraps a switch's `on` value in a bindable property.
public var rex_on: MutableProperty<Bool> {

let property = associatedProperty(self, key: &onKey, initial: { $0.on }, setter: { $0.on = $1 })

property <~ rex_controlEvents(.ValueChanged)
.filterMap { ($0 as? UISwitch)?.on }

return property
return UIControl.rex_value(self, getter: { $0.on }, setter: { $0.on = $1 })
}

}

private var onKey: UInt8 = 0
2 changes: 2 additions & 0 deletions Source/UIKit/UITableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
// Rex
//
// Created by David Rodrigues on 19/04/16.
// modified by Andrew Ware on 6/7/16.
// Copyright © 2016 Neil Pankey. All rights reserved.
//

import ReactiveCocoa
import UIKit

extension UITableViewCell: Reusable {}
23 changes: 17 additions & 6 deletions Source/UIKit/UITextField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,25 @@

import ReactiveCocoa
import UIKit
import enum Result.NoError

extension UITextField {

/// Sends the field's string value whenever it changes.
public var rex_text: SignalProducer<String, NoError> {
return NSNotificationCenter.defaultCenter()
.rac_notifications(UITextFieldTextDidChangeNotification, object: self)
.filterMap { ($0.object as? UITextField)?.text }
/// Wraps a textField's `text` value in a bindable property.
public var rex_text: MutableProperty<String?> {
let getter: UITextField -> String? = { $0.text }
let setter: (UITextField, String?) -> () = { $0.text = $1 }
#if os(iOS)
return UIControl.rex_value(self, getter: getter, setter: setter)
#else
return associatedProperty(self, key: &textKey, initial: getter, setter: setter) { property in
property <~
NSNotificationCenter.defaultCenter()
.rac_notifications(UITextFieldTextDidChangeNotification, object: self)
.filterMap { ($0.object as? UITextField)?.text }
}
#endif
}

}

private var textKey: UInt8 = 0
7 changes: 7 additions & 0 deletions Source/UIKit/UIView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ extension UIView {
public var rex_hidden: MutableProperty<Bool> {
return associatedProperty(self, key: &hiddenKey, initial: { $0.hidden }, setter: { $0.hidden = $1 })
}


/// Wraps a view's `userInteractionEnabled` state in a bindable property.
public var rex_userInteractionEnabled: MutableProperty<Bool> {
return associatedProperty(self, key: &userInteractionEnabledKey, initial: { $0.userInteractionEnabled }, setter: { $0.userInteractionEnabled = $1 })
}
}

private var alphaKey: UInt8 = 0
private var hiddenKey: UInt8 = 0
private var userInteractionEnabledKey: UInt8 = 0
13 changes: 6 additions & 7 deletions Source/UIKit/UIViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,12 @@ extension UIViewController {
host.dismissViewControllerAnimated(unwrapped.animated, completion: unwrapped.completion)
}

let property = associatedProperty(self, key: &dismissModally, initial: initial, setter: setter)

property <~ rac_signalForSelector(#selector(UIViewController.dismissViewControllerAnimated(_:completion:)))
.takeUntilBlock { _ in property.value != nil }
.rex_toTriggerSignal()
.map { _ in return nil }

let property = associatedProperty(self, key: &dismissModally, initial: initial, setter: setter) { property in
property <~ self.rac_signalForSelector(#selector(UIViewController.dismissViewControllerAnimated(_:completion:)))
.takeUntilBlock { _ in property.value != nil }
.rex_toTriggerSignal()
.map { _ in return nil }
}

return property
}
Expand Down
Loading