Sie sind auf Seite 1von 82

Reactive

Programming
By James Pang

Imperative Programming
vs

Reactive Programming

Imperative Programming
Concerned with HOW to do something to achieve
WHAT I want

Imperative Programming
Concerned with HOW to do something to achieve
WHAT I want
var
var
var
x =
z =

x
y
z
5
x

= 3
= 4
= x + y //7
+ y //9

Reactive Programming
Concerned with WHAT I want, keeping the HOW
abstracted away

Reactive Programming
Concerned with WHAT I want, keeping the HOW
abstracted away
var
var
var
x =

x
y
z
5

= 3
= 4
= x + y // 7
// z now equals 9

Reactive Programming
Concerned with WHAT I want, keeping the how
abstracted away
var
var
var
x =

x
y
z
5

= 3
= 4
= x + y // 7
// z now equals 9

Maintains the intent of your expression over time

WHY?

STATE IS HARD

ASYNC IS
HARD

State example
var array = [1, 2, 3]
//We want [2, 3, 4]

State example
var array = [1, 2, 3]
var newArray: [Int] = []
for var i = 0; i < array.count; i++ {
newArray.append(array[i] + 1)
}
newArray // [2, 3, 4]

Stateless example
var array = [1, 2, 3]
var newArray = array.map { x in return x + 1 } // [2, 3, 4]

State example

var isAlertShowing: Bool //2 states

From Justin Spahr-Summers' Enemy of the State presentation.

State example

var isAlertShowing: Bool //2 states


var isFetching: Bool //4 states

From Justin Spahr-Summers' Enemy of the State presentation.

State example

var isAlertShowing: Bool //2 states


var isFetching: Bool //4 states
var isAnimating: Bool // 8 states

From Justin Spahr-Summers' Enemy of the State presentation.

State example

var
var
var
var

isAlertShowing: Bool //2 states


isFetching: Bool //4 states
isAnimating: Bool // 8 states
isCrashing: Bool // 16 states

From Justin Spahr-Summers' Enemy of the State presentation.

State example

var
var
var
var

isAlertShowing: Bool //2 states


isLoading: Bool //4 states
isAnimating: Bool // 8 states
isCrashing: Bool // 16 states

A.K.A

Combinatorial Explosion
1

From Justin Spahr-Summers' Enemy of the State presentation.

Array
Examples

Array Example
var array = [1, 2, 3, 4, 5, 6]
//We want //[2, 4, 6]

Array Example
var array = [1, 2, 3, 4, 5, 6]
var newArray = array.filter { x in return x % 2 == 0 } // [2, 4, 6]

Array Example
var array = [1, 2, 3, 4]
//We want 10

Array Example
var array = [1, 2, 3, 4]
var sum = array.reduce(0, combine: {
previousValue, currentElement in
return previousValue + currentElement
}) // 10

Array Example
var nestedArray = [[1, 2, 3], [4, 5, 6]]
//We want [2, 3, 4, 5, 6, 7]

Array Example
var nestedArray = [[1, 2, 3], [4, 5, 6]]
var flattendArray = nestedArray.flatMap {
element in
return element.map { innerElement in
return innerElement + 1
}
} // [2, 3, 4, 5, 6, 7]

ASYNCHRONOUS

EVENTS AS ARRAYS

OVER TIME

Examples
[click...]
... = arbitrary amount of time

Examples
[click...click...]
... = arbitrary amount of time

Examples
[click...click...click...]
... = arbitrary amount of time

Examples
[click...click...click...click...]
... = arbitrary amount of time

Examples
[click...click...click...click...click...]
... = arbitrary amount of time

Examples
[click...click...click...click...click...]
[h...]
... = arbitrary amount of time

Examples
[click...click...click...click...click...]
[h...he...]
... = arbitrary amount of time

Examples
[click...click...click...click...click...]
[h...he...hel...]
... = arbitrary amount of time

Examples
[click...click...click...click...click...]
[h...he...hel...hell]
... = arbitrary amount of time

Examples
[click...click...click...click...click...]
[h...he...hel...hell...hello]
... = arbitrary amount of time

Observable

Observable
[h...]

Observable
[h...he...]

Observable
[h...he...hel...]

Observable
[h...he...hel...hell...]

Observable
[h...he...hel...hell...hello...]

Observable
[h...he...hel...hell...hello...onComplete]
OR
[h...he...hel...hell...hello...onError]

Reactive Extensions
An API for asynchronous programming with
observable streams
reactivex.io website
RxJava, RxJS, Rx.NET, RxSwift + more

EXAMPLES

EXAMPLES
Observable.just(1)

EXAMPLES
Observable.just(1)
.subscribeNext { nextValue in
print(nextValue)
}
// 1

EXAMPLES
let subscription = Observable.just(1)
.subscribeNext { nextValue in
print(nextValue)
}
// 1
subscription.dispose()

FORM
VALIDATION
EXAMPLE

FORM VALIDATION EXAMPLE


let usernameStream = usernameTextField.rx_text

FORM VALIDATION EXAMPLE


let usernameStream = usernameTextField.rx_text
let validUsernameStream = usernameStream.map { text in
return text.characters.count > 4
}

FORM VALIDATION EXAMPLE


let validUsernameStream =
usernameTextField.rx_text
.map { text in
return text.characters.count > 4
}

FORM VALIDATION EXAMPLE


let validUsernameStream =
usernameTextField.rx_text
.map { text in
return text.characters.count > 4
}
let validPasswordStream =
passwordTextField.rx_text
.map { text in
return text.characters.count > 4
}

FORM VALIDATION EXAMPLE


let validUsernameStream =
usernameTextField.rx_text
.map(validInput)
let validPasswordStream =
passwordTextField.rx_text
.map(validInput)

FORM VALIDATION EXAMPLE


let validUsernameStream =
usernameTextField.rx_text
.map(validInput)
let validPasswordStream =
passwordTextField.rx_text
.map(validInput)
let loginButtonEnabledStream = Observable.combineLatest(
validUsernameStream,
validPasswordStream,
resultSelector: { validUsername, validPassword in
return validUsername && validPassword
})

FORM VALIDATION EXAMPLE


let validUsernameStream =
usernameTextField.rx_text
.map(validInput)
let validPasswordStream =
passwordTextField.rx_text
.map(validInput)
Observable.combineLatest(
validUsernameStream,
validPasswordStream,
resultSelector: { validUsername, validPassword in
return validUsername && validPassword
})
.subscribeNext { isEnabled in
self.loginButton.enabled = isEnabled
}

FORM VALIDATION EXAMPLE


let validUsernameStream =
usernameTextField.rx_text
.map(validInput)
let validPasswordStream =
passwordTextField.rx_text
.map(validInput)
Observable.combineLatest(
validUsernameStream,
validPasswordStream,
resultSelector: { validUsername, validPassword in
return validUsername && validPassword
})
.subscribeNext { isEnabled in
self.loginButton.enabled = isEnabled
}
.addDisposableTo(disposeBag)

FORM VALIDATION EXAMPLE


let validUsernameStream =
usernameTextField.rx_text
.map(validInput)
let validPasswordStream =
passwordTextField.rx_text
.map(validInput)
Observable.combineLatest(
validUsernameStream,
validPasswordStream) {
return $0 && $1
}
.bindTo(loginButton.rx_enabled)
.addDisposableTo(disposeBag)

AUTO
COMPLETE
EXAMPLE

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.map { searchQuery in
return getSearchResults(searchQuery)
}

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.map { searchQuery in
return getSearchResults(searchQuery)
}
func getSearchResults(searchQuery: String) -> Observable<[String]> {
return Observable.create { observer in

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.map { searchQuery in
return getSearchResults(searchQuery)
}
func getSearchResults(searchQuery: String) -> Observable<[String]> {
return Observable.create { observer in
API.getSearchResults(searchQuery,
successCallback: { results in
},
errorCallback: { error in

});

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.map { searchQuery in
return getSearchResults(searchQuery)
}
func getSearchResults(searchQuery: String) -> Observable<[String]> {
return Observable.create { observer in
API.getSearchResults(searchQuery,
successCallback: { results in
observer.onNext(results)
observer.onCompleted()
},
errorCallback: { error in

});

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.map { searchQuery in
return getSearchResults(searchQuery)
}
func getSearchResults(searchQuery: String) -> Observable<[String]> {
return Observable.create { observer in
API.getSearchResults(searchQuery,
successCallback: { results in
observer.onNext(results)
observer.onCompleted()
},
errorCallback: { error in
observer.onError(error)
});
}
}

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.map { searchQuery in
return getSearchResults(searchQuery)
}
func getSearchResults(searchQuery: String) -> Observable<[String]> {
return Observable.create { observer in
API.getSearchResults(searchQuery,
successCallback: { results in
observer.onNext(results)
observer.onCompleted()
},
errorCallback: { error in
observer.onError(error)
});

return AnonymousDisposable {
API.cancel();
}

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.map { searchQuery in
return getSearchResults(searchQuery)
}
func getSearchResults(searchQuery: String) -> Observable<[String]> {
return Observable.create { observer in
API.getSearchResults(searchQuery,
successCallback: { results in
observer.onNext(results)
observer.onCompleted()
},
errorCallback: { error in
observer.onError(error)
});

return AnonymousDisposable {
API.cancel();
}

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.flatMap { searchQuery in
return getSearchResults(searchQuery)
}
func getSearchResults(searchQuery: String) -> Observable<[String]> {
return Observable.create { observer in
API.getSearchResults(searchQuery,
successCallback: { results in
observer.onNext(results)
observer.onCompleted()
},
errorCallback: { error in
observer.onError(error)
});
}
}

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.flatMap { searchQuery in
return getSearchResults(searchQuery)
}

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.flatMap { searchQuery in
return getSearchResults(searchQuery)
}

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.flatMap { searchQuery in
return getSearchResults(searchQuery)
.retry(3)
}

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.flatMapLatest { searchQuery in
return self.getSearchResults(searchQuery)
.retry(3)
}

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.debounce(0.4, scheduler: MainScheduler.instance)
.flatMapLatest { searchQuery in
return self.getSearchResults(searchQuery)
.retry(3)
}

AUTO COMPLETE EXAMPLE


let searchStream =
searchTextField.rx_text
.debounce(0.4, scheduler: MainScheduler.instance)
.distinctUntilChanged()
.flatMapLatest { searchQuery in
return self.getSearchResults(searchQuery)
.retry(3)
}

AUTO COMPLETE EXAMPLE


searchTextField.rx_text
.debounce(0.4, scheduler: MainScheduler.instance)
.distinctUntilChanged()
.flatMapLatest { searchQuery in
return self.getSearchResults(searchQuery)
.retry(3)
}
.subscribeNext { searchResults in
print(searchResults)
}
.addDisposableTo(disposeBag)

MULTIPLE API
EXAMPLE

MULTIPLE API EXAMPLE


let loginClickStream = loginButton.rx_tap

MULTIPLE API EXAMPLE


loginButton.rx_tap
.flatMapLatest { clickValue in
return Observable.combineLatest(
self.getFriendsList(),
self.getNewsFeed(),
self.getPrivateMessages()) {
friends, newsFeedPosts, privateMessages in
return (friends, newsFeedPosts, privateMessages)
}
}
}

MULTIPLE API EXAMPLE


loginButton.rx_tap
.flatMapLatest { clickValue in
return Observable.combineLatest(
self.getFriendsList(),
self.getNewsFeed(),
self.getPrivateMessages()) {
friends, newsFeedPosts, privateMessages in
return (friends, newsFeedPosts, privateMessages)
}
}
.subscribeNext { combinedResults in
print(combinedResults.0) // Friends
print(combinedResults.1) // News Feed Posts
print(combinedResults.2) // Private Messages
//Screen rendering
}
.addDisposableTo(disposeBag)
}

Unified API
across
languagues

Links
http://rxmarbles.com/
https://www.youtube.com/watch?v=XE692Clb5LU
http://reactivex.io/learnrx/
https://gist.github.com/staltz/868e7e9bc2a7b8c1f754

Thank you!

Das könnte Ihnen auch gefallen