SlideShare une entreprise Scribd logo
1  sur  79
Télécharger pour lire hors ligne
letswift(16)
RxSwift 시작하기
최완복
class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var button: UIButton!
@IBOutlet weak var passwordField: UITextField!
@IBOutlet weak var signInButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
self.textField.rac_textSignal().subscribeNext { (x) -> Void in
println(x)
}
let textSignal = self.textField.rac_textSignal().map { (x) -> AnyObject! in
NSNumber(bool: ((x as? NSString) ?? "").rangeOfString("@").location != NSNotFound)
} //NSNumber (boolean)
let colorSignal = textSignal.map { x in
((x as? NSNumber)?.boolValue ?? false) ? UIColor.greenColor() : UIColor.redColor()
} // UICOlor
//textSignal ~> RAC(button, "enabled")
colorSignal ~> RAC(textField, "textColor")
let passwordSignal = self.passwordField.rac_textSignal().map { x in
NSNumber(bool: (x as? NSString ?? "").length > 4)
} //NSNumber
let formValidSignal = RACSignal.combineLatest([textSignal, passwordSignal]).map {
let tuple = $0 as! RACTuple
let bools = tuple.allObjects() as! [Bool]
return NSNumber(bool: bools[0] == true && bools[1] == true)
}
formValidSignal ~> RAC(signInButton, "enabled")
button.rac_command = RACCommand(enabled: textSignal, signalBlock: { (x) -> RACSignal! in
println("pressed")
return RACSignal.empty()
})
}
}
Rx?
Reactive
Extensions
In computing, reactive programming is a programming
paradigm oriented around data flows and the propagation of
change.
Reactive Programming
Functional reactive programming (FRP) is a programming
paradigm for reactive programming (asynchronous dataflow
programming) using the building blocks of functional
programming (e.g. map, reduce, filter).
Functional Reactive Programming
Functional Reactive Programming
functional programming data flows propagation of change
Functional Programming
1 부터 10까지 더하는 문제
var sum = 0
for i in 1...10 {
sum += 1
}
print(sum)
Procedural way
print((1...10).reduce(0) { $0 + $1 })
Functional way
Data Flow
(1...10)
.filter {
$0 % 2 == 0 // 2, 4, 6, 8, 10
}
.map {
$0 * 10 // 20, 40, 60, 80, 100
}
.reduce(0) {
$0 + $1 // 300
}
Propagation of Change
(1...5)
.filter {
$0 % 2 == 0 // 2, 4
}
.map {
$0 * 10 // 20, 40
}
.reduce(0) {
$0 + $1 // 60
}
Propagation of Change
(1...5)
.filter {
$0 % 2 == 0 // 2, 4
}
.map {
$0 * 100 // 200, 400
}
.reduce(0) {
$0 + $1 // 600
}
ReactiveX
http://reactivex.io/
An API for asynchronous programming
with observable streams
단일 다수
동기 Try<T> Iterable<T>
비동기 Future<T> Observable<T>
Observable
Operate
Subscribe
onNext
onError
onCompleted
Iterable(pull) Observable(push)
데이터받기 T next() onNext (T)
에러 발견 throws Exception onError(Exception)
완료 !hasNext() onCompleted()
Observable.create<String> { observer in
observer.onNext("🐶")
observer.onNext("🐱")
observer.onNext("👽")
observer.onCompleted()
}
.subscribe {
print($0)
}
>> “🐶”..”🐱”.."👽" >>
우선 만져보자
pod try RxSwift
import RxSwift
.subscribe { (event) in
print(event)
}
.distinctUntilChanged()
🐶 🐱 👽🐱
🐱🐶 🐶
🐶
👽
["🐶", "🐱", "🐱", "🐶", "👽"].toObservable()
import RxSwift
.subscribe { (event) in
print(event)
}
.distinctUntilChanged()
🐶 🐱 👽🐱
🐱🐶 🐶
🐶
👽
["🐶", "🐱", "🐱", "🐶", "👽"].toObservable()
import RxSwift
.subscribe { (event) in
print(event)
}
.distinctUntilChanged()
🐶 🐱 👽🐱
🐱🐶 🐶
🐶
👽🐱
Next(🐶)
Next(🐱)
Next(🐱)
Next(🐶)
Next(👽)
Completed
["🐶", "🐱", "🐱", "🐶", "👽"].toObservable()
import RxSwift
.subscribe { (event) in
print(event)
}
.distinctUntilChanged()
🐶 🐱 👽🐱
🐱🐶 🐶
🐶
👽
Next(🐶)
Next(🐱)
Next(🐶)
Next(👽)
Completed
["🐶", "🐱", "🐱", "🐶", "👽"].toObservable()
import RxSwift
.subscribe { (event) in
print(event)
}
.distinctUntilChanged()
.addDisposableTo(disposeBag)
Disposable
DisposableDisposableDisposableDisposableDisposableDisposableDisposable
["🐶", "🐱", "🐱", "🐶", "👽"].toObservable()
import RxSwift
.subscribe { (event) in
print(event)
}
.distinctUntilChanged()
.dispose()
Creating Observables
asObservable, create, deferred, empty, error, toObservable (array), interval, never, just, of, range, repeatElement, timer
Transforming Observables
buffer, flatMap, flatMapFirst, flatMapLatest, map, scan, window
Filtering Observables
debounce / throttle, distinctUntilChanged, elementAt, filter, sample, skip, take, takeLast, single
Combining Observables
merge, startWith, switchLatest, combineLatest, zip
Error Handling Operators
catch, retry, retryWhen
Observable Utility Operators
delaySubscription, do / doOnNext, observeOn / observeSingleOn, subscribe, subscribeOn, timeout, using, debug
Conditional and Boolean Operators
amb, skipWhile, skipUntil, takeUntil, takeWhile
Mathematical and Aggregate Operators
concat, reduce / aggregate, toArray
Connectable Observable Operators
multicast, publish, refCount, replay, shareReplay
let sequenceThatErrors = Observable<String>.create { observer in
observer.onNext("🍎")
observer.onNext("🍐")
observer.onNext("🍊")
if isGoingWrong {
observer.onError(Error.Test)
print("Error encountered")
count += 1
}
observer.onNext("🐶")
observer.onNext("🐱")
observer.onNext("🐭")
observer.onCompleted()
return NopDisposable.instance
}
————result————
🍎
🍐
🍊
Error encountered
sequenceThatErrors
.subscribeNext { print($0) }
.addDisposableTo(disposeBag)
🍊🍐🍎
import UIKit
import RxSwift
import RxCocoa
class EmailLoginViewController: UIViewController {
let disposeBag = DisposeBag()
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var passwordTextField: UITextField!
@IBOutlet weak var loginButton: UIButton!
…
@IBAction func onLogin(sender: UIButton) {
guard let email = emailTextField?.text,
password = passwordTextField?.text
else {
return
}
Router.EmailLogin(["email": email, "password": password]).request
.responseJSON { [weak self] response in
let json = JSON(response.result.value!)
let user = User(json: json)
}
}
// MARK: UIViewController implements
override func viewDidLoad() {
super.viewDidLoad()
}
}
Login
Validator
import UIKit
import RxSwift
import RxCocoa
class EmailLoginViewController: UIViewController {
let disposeBag = DisposeBag()
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var passwordTextField: UITextField!
@IBOutlet weak var loginButton: UIButton!
…
@IBAction func onLogin(sender: UIButton) {
guard let email = emailTextField?.text,
password = passwordTextField?.text
else {
return
}
Router.EmailLogin(["email": email, "password": password]).request
.responseJSON { [weak self] response in
let json = JSON(response.result.value!)
let user = User(json: json)
self?.succeedToLogin(user)
}
}
// MARK: UIViewController implements
override func viewDidLoad() {
super.viewDidLoad()
}
}
1. 이메일형식을 체크
2. 패스워드는 6자리 이상
3. 이메일/패스워드가 비어있을때, 입력을 요구한다.
1. 이메일형식을 체크
2. 패스워드는 6자리 이상
3. 이메일/패스워드가 비어있을때, 입력을 요구한다.
emailTextField.rx_text.asObservable()
import RxSwift
import RxCocoa
a@b.c
.subscribeNext { print($0) }
a
a@
a@b
a@b.
a@b.c
.addDisposableTo(disposeBag)
emailTextField.rx_text.asObservable()
import RxSwift
import RxCocoa
.subscribeNext {
let isValid = $0.isEmail || $0.isEmpty
}
.addDisposableTo(disposeBag)
emailTextField.rx_text.asObservable()
import RxSwift
import RxCocoa
.subscribeNext {
let isValid = $0.isEmail || $0.isEmpty
}
.addDisposableTo(disposeBag)
emailTextField.rx_text.asObservable()
import RxSwift
import RxCocoa
.map { $0.isEmail || $0.isEmpty }
.addDisposableTo(disposeBag)
.subscribeNext {
print($0)
}
emailTextField.rx_text.asObservable()
import RxSwift
import RxCocoa
.map { $0.isEmail || $0.isEmpty }
.subscribeNext {
self.emailTextField.backgroundColor =
$0 ? UIColor.whiteColor() : UIColor.alertColor
}
.addDisposableTo(disposeBag)
1. 이메일형식을 체크
2. 패스워드는 6자리 이상
3. 이메일/패스워드가 비어있을때, 입력을 요구한다.
passwordTextField.rx_text.asObservable()
import RxSwift
import RxCocoa
.map { !(1..<6 ~= $0.characters.count) }
.subscribeNext {
self.passwordTextField.backgroundColor =
$0 ? UIColor.whiteColor() : UIColor.alertColor
}
.addDisposableTo(disposeBag)
1. 이메일형식을 체크
2. 패스워드는 6자리 이상
3. 이메일/패스워드가 비어있을때, 입력을 요구한다.
emailTextField.rx_text.asObservable()
import RxSwift
import RxCocoa
.subscribeNext {
let buttonTitle = $0 ? "이메일을 입력하세요" : "로그인 하기"
self.loginButton?.setTitle(buttonTitle, forState: .Normal)
}
.addDisposableTo(disposeBag)
.map { $0.isEmpty }
passwordTextField.rx_text.asObservable()
import RxSwift
import RxCocoa
.subscribeNext {
let buttonTitle = $0 ? "패스워드를 입력하세요" : "로그인 하기"
self.loginButton?.setTitle(buttonTitle, forState: .Normal)
}
.addDisposableTo(disposeBag)
.map { $0.isEmpty }
http://rxmarbles.com/
let emailEmptyObservable = emailTextField.rx_text.asObservable()
.map { $0.isEmpty }
let passwordEmptyObservable = passwordTextField.rx_text.asObservable()
.map { $0.isEmpty }
a a@ a@b a@b.ca@b.
.map { $0.isEmpty }
true false false false falsefalse
“”
Observable
.combineLatest(emailEmptyObservable, passwordEmptyObservable) {
return ($0, $1)
}
true false false
false falsetrue
(true, true) (false, true) (false, true)
false
.combineLatest(email, pass) { return ($0, $1) }
(false, false) (false, false)(false, false)
let emailEmptyObservable = emailTextField.rx_text.asObservable()
.map { $0.isEmpty }
let passwordEmptyObservable = passwordTextField.rx_text.asObservable()
.map { $0.isEmpty }
Observable
.combineLatest(emailEmptyObservable, passwordEmptyObservable) {
return ($0, $1)
}
.subscribeNext { tuple in
let buttonTitle: String = {
switch tuple {
case (true, true): return "이메일/패스워드를 입력하세요"
case (true, _): return "이메일을 입력하세요"
case (_, true): return "패스워드를 입력하세요"
default: return "로그인 하기"
}
}()
self.registerButton?.setTitle(buttonTitle, forState: .Normal)
self.registerButton?.backgroundColor =
tuple.0 || tuple.1 ? UIColor.gray4AColor : UIColor.tintColor
}
.addDisposableTo(disposeBag)
import UIKit
import RxSwift
import RxCocoa
class EmailLoginViewController: UIViewController {
let disposeBag = DisposeBag()
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var passwordTextField: UITextField!
@IBOutlet weak var loginButton: UIButton!
…
// MARK: UIViewController implements
override func viewDidLoad() {
super.viewDidLoad()
addValidations()
}
func addValidations() {
…
}
}
func addValidations() {
let emailEmptyObservable = emailTextField.rx_text.asObservable().map { $0.isEmpty }
let passwordEmptyObservable = passwordTextField.rx_text.asObservable().map { $0.isEmpty }
Observable
.combineLatest(emailEmptyObservable, passwordEmptyObservable) {
return ($0, $1)
}
.subscribeNext { tuple in
let buttonTitle: String = {
switch tuple {
case (true, true): return "이메일/패스워드를 입력하세요"
case (true, _): return "이메일을 입력하세요"
case (_, true): return "패스워드를 입력하세요"
default: return "로그인 하기"
}
}()
self.registerButton?.setTitle(buttonTitle, forState: .Normal)
self.registerButton?.backgroundColor = tuple.0 || tuple.1 ? UIColor.gray4AColor : UIColor.tintColor
}
.addDisposableTo(disposeBag)
emailTextField.rx_text.asObservable()
.map { $0.isEmail || $0.isEmpty }
.subscribeNext {
self.emailTextField.backgroundColor = $0 ? UIColor.whiteColor() : UIColor.alertColor
}
.addDisposableTo(disposeBag)
passwordTextField.rx_text.asObservable()
.map { !(1..<6 ~= $0.characters.count) }
.subscribeNext {
self.passwordTextField.backgroundColor = $0 ? UIColor.whiteColor() : UIColor.alertColor
}
.addDisposableTo(disposeBag)
}
Wrapping
Alamofire.Request
enum Router: URLRequestConvertible {
case Collection(Int)
var request: Alamofire.Request {
return HTTPManager.sharedHTTPManager.request(self)
}
var method: Alamofire.Method {
return .GET
}
var path: String {
switch self {
case .Collection(let id): return “/Collections/(id)"
}
}
var parameters: Parameter {
switch self {
case .Collection: return ["filter": ["include": ["images"]]]
}
}
// MARK: URLRequestConvertible
var URLRequest: NSMutableURLRequest {
let URL = NSURL(string: Router.baseURLString)!
let mutableURLRequest = NSMutableURLRequest(URL: URL.URLByAppendingPathComponent(path))
mutableURLRequest.HTTPMethod = method.rawValue
return Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: parameters).0
}
}
}
let collections = Variable([Collection]())
Router.Collections(["filter": filterParameter]).request
.validate()
.responseJSON { [weak self] response in
if let value = response.result.value {
let newData = Collection.array(JSON(value))
self?.collections.value = newData
return
}
}
extension Alamofire.Request {
func rx_validateSuccessfulResponse() -> Request {
……
}
public func rx_result<T: ResponseSerializerType>(
queue queue: dispatch_queue_t? = nil,
responseSerializer: T)
-> Observable<T.SerializedObject>
{
return Observable.create { [weak self] observer in
self?
.rx_validateSuccessfulResponse()
.response(queue: queue, responseSerializer: responseSerializer) { _response in
switch _response.result {
case .Success(let result):
if let _ = _response.response {
observer.on(.Next(result))
} else {
observer.on(.Error(NSError(domain: "Frip", code: -1, userInfo: nil)))
}
observer.on(.Completed)
case .Failure(let error):
observer.on(.Error(error as ErrorType))
}
}
return NopDisposable.instance
}
}
public func rx_JSON(options options: NSJSONReadingOptions = .AllowFragments)
-> Observable<AnyObject>
{
return rx_result(responseSerializer: Request.JSONResponseSerializer(options: options))
}
}
.response(queue: queue, responseSerializer: responseSerializer) { _response in
switch _response.result {
case .Success(let result):
if let _ = _response.response {
observer.on(.Next(result))
} else {
observer.on(.Error(NSError(domain: "Frip", code: -1, userInfo: nil)))
}
observer.on(.Completed)
case .Failure(let error):
observer.on(.Error(error as ErrorType))
}
}
let collections = Variable([Collection]())
Router.Collections(["filter": filterParameter]).request
.rx_JSON()
.retry(1)
.startWith([])
.catchErrorJustReturn([])
.bindTo(collections)
let collections = Variable([Collection]())
Router.Collections(["filter": filterParameter]).request
.rx_JSON()
.retry(1)
.startWith([])
.catchErrorJustReturn([])
.bindTo(collections)
.retry(1)
let collections = Variable([Collection]())
Router.Collections(["filter": filterParameter]).request
.rx_JSON()
.retry(1)
.startWith([])
.catchErrorJustReturn([])
.bindTo(collections)
.startWith([])
[ ] [Collection, …, Collection]
let collections = Variable([Collection]())
Router.Collections(["filter": filterParameter]).request
.rx_JSON()
.retry(1)
.startWith([])
.catchErrorJustReturn([])
.bindTo(collections)
.catchErrorJustReturn([])
[ ]
let collections = Variable([Collection]())
Router.Collections(["filter": filterParameter]).request
.rx_JSON()
.retry(1)
.startWith([])
.catchErrorJustReturn([])
.bindTo(collections)
.bindTo(collections)
[ ] […] […] […]
https://github.com/RxSwiftCommunity/RxAlamofire
RxAlamofire
더 알아보기
https://github.com/RxSwiftCommunity
RxSwift Community
https://justhackem.wordpress.com/2015/03/19/rmvvm-architecture/
Reactive MVVM(Model-View-ViewModel) 모바일 응용프로그램 아키텍쳐
https://github.com/devxoul/RxTodo
RxTodo
References
ReactiveX.io
https://github.com/ReactiveX/RxSwift
http://www.introtorx.com/
http://mobicon.tistory.com/467
http://www.slideshare.net/sunhyouplee/functional-reactive-
programming-with-rxswift-62123571
http://www.slideshare.net/deview/1b4-39616041
http://www.slideshare.net/gmind7/springcamp2015-rxjava
http://www.slideshare.net/jongwookkim/ndc14-rx-functional-reactive-
programminghttps://justhackem.wordpress.com/2015/03/19/rmvvm-
architecture/
https://github.com/devxoul/RxTodo
감사합니다.
letswift(16)

Contenu connexe

Tendances

ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016Manoj Kumar
 
Building fast interpreters in Rust
Building fast interpreters in RustBuilding fast interpreters in Rust
Building fast interpreters in RustIngvar Stepanyan
 
Reactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaReactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaHermann Hueck
 
Functional Algebra: Monoids Applied
Functional Algebra: Monoids AppliedFunctional Algebra: Monoids Applied
Functional Algebra: Monoids AppliedSusan Potter
 
Developer Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duoDeveloper Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duoThe Software House
 
Proxies are Awesome!
Proxies are Awesome!Proxies are Awesome!
Proxies are Awesome!Brendan Eich
 
JavaScript Tutorial
JavaScript  TutorialJavaScript  Tutorial
JavaScript TutorialBui Kiet
 
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Susan Potter
 
ES6 - Next Generation Javascript
ES6 - Next Generation JavascriptES6 - Next Generation Javascript
ES6 - Next Generation JavascriptRamesh Nair
 
5 Tips for Better JavaScript
5 Tips for Better JavaScript5 Tips for Better JavaScript
5 Tips for Better JavaScriptTodd Anglin
 
Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)jeffz
 
Hardened JavaScript
Hardened JavaScriptHardened JavaScript
Hardened JavaScriptKrisKowal2
 
Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.boyney123
 
JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6Solution4Future
 

Tendances (20)

Rust ⇋ JavaScript
Rust ⇋ JavaScriptRust ⇋ JavaScript
Rust ⇋ JavaScript
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
 
Building fast interpreters in Rust
Building fast interpreters in RustBuilding fast interpreters in Rust
Building fast interpreters in Rust
 
JavaScript Basics and Trends
JavaScript Basics and TrendsJavaScript Basics and Trends
JavaScript Basics and Trends
 
Reactive Access to MongoDB from Scala
Reactive Access to MongoDB from ScalaReactive Access to MongoDB from Scala
Reactive Access to MongoDB from Scala
 
Functional Algebra: Monoids Applied
Functional Algebra: Monoids AppliedFunctional Algebra: Monoids Applied
Functional Algebra: Monoids Applied
 
Developer Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duoDeveloper Experience i TypeScript. Najbardziej ikoniczne duo
Developer Experience i TypeScript. Najbardziej ikoniczne duo
 
Proxies are Awesome!
Proxies are Awesome!Proxies are Awesome!
Proxies are Awesome!
 
JavaScript Tutorial
JavaScript  TutorialJavaScript  Tutorial
JavaScript Tutorial
 
Anonymous functions in JavaScript
Anonymous functions in JavaScriptAnonymous functions in JavaScript
Anonymous functions in JavaScript
 
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
Scalaz By Example (An IO Taster) -- PDXScala Meetup Jan 2014
 
Intro to JavaScript
Intro to JavaScriptIntro to JavaScript
Intro to JavaScript
 
ES6 - Next Generation Javascript
ES6 - Next Generation JavascriptES6 - Next Generation Javascript
ES6 - Next Generation Javascript
 
ddd+scala
ddd+scaladdd+scala
ddd+scala
 
5 Tips for Better JavaScript
5 Tips for Better JavaScript5 Tips for Better JavaScript
5 Tips for Better JavaScript
 
Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)
 
Hardened JavaScript
Hardened JavaScriptHardened JavaScript
Hardened JavaScript
 
Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.
 
JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6
 
ECMAScript 6
ECMAScript 6ECMAScript 6
ECMAScript 6
 

En vedette

Swift에서 꼬리재귀 사용기 (Tail Recursion)
Swift에서 꼬리재귀 사용기 (Tail Recursion)Swift에서 꼬리재귀 사용기 (Tail Recursion)
Swift에서 꼬리재귀 사용기 (Tail Recursion)진성 오
 
프알못의 Realm 사용기
프알못의 Realm 사용기프알못의 Realm 사용기
프알못의 Realm 사용기Mijeong Jeon
 
Swift and Xcode8
Swift and Xcode8Swift and Xcode8
Swift and Xcode8Hyuk Hur
 
Swift package manager
Swift package managerSwift package manager
Swift package manager성관 윤
 
안드로이드 개발자를 위한 스위프트
안드로이드 개발자를 위한 스위프트안드로이드 개발자를 위한 스위프트
안드로이드 개발자를 위한 스위프트병한 유
 
Swift server-side-let swift2016
Swift server-side-let swift2016Swift server-side-let swift2016
Swift server-side-let swift2016Eric Ahn
 
Do swift: Swift 무작정 해보기
Do swift: Swift 무작정 해보기Do swift: Swift 무작정 해보기
Do swift: Swift 무작정 해보기YoonBong Steve Kim
 
Protocol Oriented Programming in Swift
Protocol Oriented Programming in SwiftProtocol Oriented Programming in Swift
Protocol Oriented Programming in SwiftSeongGyu Jo
 
스위프트 성능 이해하기
스위프트 성능 이해하기스위프트 성능 이해하기
스위프트 성능 이해하기Yongha Yoo
 
NDC14 - Rx와 Functional Reactive Programming으로 고성능 서버 만들기
NDC14 - Rx와 Functional Reactive Programming으로 고성능 서버 만들기NDC14 - Rx와 Functional Reactive Programming으로 고성능 서버 만들기
NDC14 - Rx와 Functional Reactive Programming으로 고성능 서버 만들기Jong Wook Kim
 
Functional Reactive Programming With RxSwift
Functional Reactive Programming With RxSwiftFunctional Reactive Programming With RxSwift
Functional Reactive Programming With RxSwift선협 이
 
[1B4]안드로이드 동시성_프로그래밍
[1B4]안드로이드 동시성_프로그래밍[1B4]안드로이드 동시성_프로그래밍
[1B4]안드로이드 동시성_프로그래밍NAVER D2
 
Functional Reactive Programming with RxJS
Functional Reactive Programming with RxJSFunctional Reactive Programming with RxJS
Functional Reactive Programming with RxJSstefanmayer13
 
Cascadia.js: Don't Cross the Streams
Cascadia.js: Don't Cross the StreamsCascadia.js: Don't Cross the Streams
Cascadia.js: Don't Cross the Streamsmattpodwysocki
 
RxJS and Reactive Programming - Modern Web UI - May 2015
RxJS and Reactive Programming - Modern Web UI - May 2015RxJS and Reactive Programming - Modern Web UI - May 2015
RxJS and Reactive Programming - Modern Web UI - May 2015Ben Lesh
 
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015NAVER / MusicPlatform
 

En vedette (16)

Swift에서 꼬리재귀 사용기 (Tail Recursion)
Swift에서 꼬리재귀 사용기 (Tail Recursion)Swift에서 꼬리재귀 사용기 (Tail Recursion)
Swift에서 꼬리재귀 사용기 (Tail Recursion)
 
프알못의 Realm 사용기
프알못의 Realm 사용기프알못의 Realm 사용기
프알못의 Realm 사용기
 
Swift and Xcode8
Swift and Xcode8Swift and Xcode8
Swift and Xcode8
 
Swift package manager
Swift package managerSwift package manager
Swift package manager
 
안드로이드 개발자를 위한 스위프트
안드로이드 개발자를 위한 스위프트안드로이드 개발자를 위한 스위프트
안드로이드 개발자를 위한 스위프트
 
Swift server-side-let swift2016
Swift server-side-let swift2016Swift server-side-let swift2016
Swift server-side-let swift2016
 
Do swift: Swift 무작정 해보기
Do swift: Swift 무작정 해보기Do swift: Swift 무작정 해보기
Do swift: Swift 무작정 해보기
 
Protocol Oriented Programming in Swift
Protocol Oriented Programming in SwiftProtocol Oriented Programming in Swift
Protocol Oriented Programming in Swift
 
스위프트 성능 이해하기
스위프트 성능 이해하기스위프트 성능 이해하기
스위프트 성능 이해하기
 
NDC14 - Rx와 Functional Reactive Programming으로 고성능 서버 만들기
NDC14 - Rx와 Functional Reactive Programming으로 고성능 서버 만들기NDC14 - Rx와 Functional Reactive Programming으로 고성능 서버 만들기
NDC14 - Rx와 Functional Reactive Programming으로 고성능 서버 만들기
 
Functional Reactive Programming With RxSwift
Functional Reactive Programming With RxSwiftFunctional Reactive Programming With RxSwift
Functional Reactive Programming With RxSwift
 
[1B4]안드로이드 동시성_프로그래밍
[1B4]안드로이드 동시성_프로그래밍[1B4]안드로이드 동시성_프로그래밍
[1B4]안드로이드 동시성_프로그래밍
 
Functional Reactive Programming with RxJS
Functional Reactive Programming with RxJSFunctional Reactive Programming with RxJS
Functional Reactive Programming with RxJS
 
Cascadia.js: Don't Cross the Streams
Cascadia.js: Don't Cross the StreamsCascadia.js: Don't Cross the Streams
Cascadia.js: Don't Cross the Streams
 
RxJS and Reactive Programming - Modern Web UI - May 2015
RxJS and Reactive Programming - Modern Web UI - May 2015RxJS and Reactive Programming - Modern Web UI - May 2015
RxJS and Reactive Programming - Modern Web UI - May 2015
 
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015
 

Similaire à LetSwift RxSwift 시작하기

Java 8 Puzzlers [as presented at OSCON 2016]
Java 8 Puzzlers [as presented at  OSCON 2016]Java 8 Puzzlers [as presented at  OSCON 2016]
Java 8 Puzzlers [as presented at OSCON 2016]Baruch Sadogursky
 
Functional Principles for OO Developers
Functional Principles for OO DevelopersFunctional Principles for OO Developers
Functional Principles for OO Developersjessitron
 
Introduction aux Macros
Introduction aux MacrosIntroduction aux Macros
Introduction aux Macrosunivalence
 
Transaction is a monad
Transaction is a  monadTransaction is a  monad
Transaction is a monadJarek Ratajski
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Jonas Bonér
 
Pragmatic Real-World Scala
Pragmatic Real-World ScalaPragmatic Real-World Scala
Pragmatic Real-World Scalaparag978978
 
ViewController.swift Calculatorimport Cocoaimport UIKit.pdf
 ViewController.swift Calculatorimport Cocoaimport UIKit.pdf ViewController.swift Calculatorimport Cocoaimport UIKit.pdf
ViewController.swift Calculatorimport Cocoaimport UIKit.pdfarasanlethers
 
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinAsync code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinFabio Collini
 
"Kotlin и rx в android" Дмитрий Воронин (Avito)
"Kotlin и rx в android" Дмитрий Воронин  (Avito)"Kotlin и rx в android" Дмитрий Воронин  (Avito)
"Kotlin и rx в android" Дмитрий Воронин (Avito)AvitoTech
 
Javascript And J Query
Javascript And J QueryJavascript And J Query
Javascript And J Queryitsarsalan
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
Kotlin Austin Droids April 14 2016
Kotlin Austin Droids April 14 2016Kotlin Austin Droids April 14 2016
Kotlin Austin Droids April 14 2016DesertJames
 
Category theory, Monads, and Duality in the world of (BIG) Data
Category theory, Monads, and Duality in the world of (BIG) DataCategory theory, Monads, and Duality in the world of (BIG) Data
Category theory, Monads, and Duality in the world of (BIG) Datagreenwop
 
Reactive Thinking in iOS Development - Pedro Piñera Buendía - Codemotion Amst...
Reactive Thinking in iOS Development - Pedro Piñera Buendía - Codemotion Amst...Reactive Thinking in iOS Development - Pedro Piñera Buendía - Codemotion Amst...
Reactive Thinking in iOS Development - Pedro Piñera Buendía - Codemotion Amst...Codemotion
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
code for quiz in my sql
code for quiz  in my sql code for quiz  in my sql
code for quiz in my sql JOYITAKUNDU1
 

Similaire à LetSwift RxSwift 시작하기 (20)

Java 8 Puzzlers [as presented at OSCON 2016]
Java 8 Puzzlers [as presented at  OSCON 2016]Java 8 Puzzlers [as presented at  OSCON 2016]
Java 8 Puzzlers [as presented at OSCON 2016]
 
Functional Principles for OO Developers
Functional Principles for OO DevelopersFunctional Principles for OO Developers
Functional Principles for OO Developers
 
Introduction aux Macros
Introduction aux MacrosIntroduction aux Macros
Introduction aux Macros
 
Transaction is a monad
Transaction is a  monadTransaction is a  monad
Transaction is a monad
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)
 
Pragmatic Real-World Scala
Pragmatic Real-World ScalaPragmatic Real-World Scala
Pragmatic Real-World Scala
 
ViewController.swift Calculatorimport Cocoaimport UIKit.pdf
 ViewController.swift Calculatorimport Cocoaimport UIKit.pdf ViewController.swift Calculatorimport Cocoaimport UIKit.pdf
ViewController.swift Calculatorimport Cocoaimport UIKit.pdf
 
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinAsync code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
 
Miracle of std lib
Miracle of std libMiracle of std lib
Miracle of std lib
 
"Kotlin и rx в android" Дмитрий Воронин (Avito)
"Kotlin и rx в android" Дмитрий Воронин  (Avito)"Kotlin и rx в android" Дмитрий Воронин  (Avito)
"Kotlin и rx в android" Дмитрий Воронин (Avito)
 
Javascript And J Query
Javascript And J QueryJavascript And J Query
Javascript And J Query
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
Kotlin Austin Droids April 14 2016
Kotlin Austin Droids April 14 2016Kotlin Austin Droids April 14 2016
Kotlin Austin Droids April 14 2016
 
Category theory, Monads, and Duality in the world of (BIG) Data
Category theory, Monads, and Duality in the world of (BIG) DataCategory theory, Monads, and Duality in the world of (BIG) Data
Category theory, Monads, and Duality in the world of (BIG) Data
 
Reactive Thinking in iOS Development - Pedro Piñera Buendía - Codemotion Amst...
Reactive Thinking in iOS Development - Pedro Piñera Buendía - Codemotion Amst...Reactive Thinking in iOS Development - Pedro Piñera Buendía - Codemotion Amst...
Reactive Thinking in iOS Development - Pedro Piñera Buendía - Codemotion Amst...
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
code for quiz in my sql
code for quiz  in my sql code for quiz  in my sql
code for quiz in my sql
 

Plus de Wanbok Choi

[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵Wanbok Choi
 
WWDC 2019 Cheatsheet
WWDC 2019 CheatsheetWWDC 2019 Cheatsheet
WWDC 2019 CheatsheetWanbok Choi
 
iOS 개발자의 Flutter 체험기
iOS 개발자의 Flutter 체험기iOS 개발자의 Flutter 체험기
iOS 개발자의 Flutter 체험기Wanbok Choi
 
[이모콘 2018 S/S] Swift로 코인 트레이딩 봇 만들기
[이모콘 2018 S/S] Swift로 코인 트레이딩 봇 만들기[이모콘 2018 S/S] Swift로 코인 트레이딩 봇 만들기
[이모콘 2018 S/S] Swift로 코인 트레이딩 봇 만들기Wanbok Choi
 
try! Swift Tokyo 2017 후기
try! Swift Tokyo 2017 후기try! Swift Tokyo 2017 후기
try! Swift Tokyo 2017 후기Wanbok Choi
 
기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017Wanbok Choi
 
06 멀티뷰 애플리케이션
06 멀티뷰 애플리케이션06 멀티뷰 애플리케이션
06 멀티뷰 애플리케이션Wanbok Choi
 
04 안드로이드 응용프로그램의 구조
04 안드로이드 응용프로그램의 구조04 안드로이드 응용프로그램의 구조
04 안드로이드 응용프로그램의 구조Wanbok Choi
 

Plus de Wanbok Choi (8)

[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
 
WWDC 2019 Cheatsheet
WWDC 2019 CheatsheetWWDC 2019 Cheatsheet
WWDC 2019 Cheatsheet
 
iOS 개발자의 Flutter 체험기
iOS 개발자의 Flutter 체험기iOS 개발자의 Flutter 체험기
iOS 개발자의 Flutter 체험기
 
[이모콘 2018 S/S] Swift로 코인 트레이딩 봇 만들기
[이모콘 2018 S/S] Swift로 코인 트레이딩 봇 만들기[이모콘 2018 S/S] Swift로 코인 트레이딩 봇 만들기
[이모콘 2018 S/S] Swift로 코인 트레이딩 봇 만들기
 
try! Swift Tokyo 2017 후기
try! Swift Tokyo 2017 후기try! Swift Tokyo 2017 후기
try! Swift Tokyo 2017 후기
 
기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
 
06 멀티뷰 애플리케이션
06 멀티뷰 애플리케이션06 멀티뷰 애플리케이션
06 멀티뷰 애플리케이션
 
04 안드로이드 응용프로그램의 구조
04 안드로이드 응용프로그램의 구조04 안드로이드 응용프로그램의 구조
04 안드로이드 응용프로그램의 구조
 

Dernier

Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfCionsystems
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 

Dernier (20)

Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdf
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 

LetSwift RxSwift 시작하기

  • 2.
  • 3. class ViewController: UIViewController { @IBOutlet weak var textField: UITextField! @IBOutlet weak var button: UIButton! @IBOutlet weak var passwordField: UITextField! @IBOutlet weak var signInButton: UIButton! override func viewDidLoad() { super.viewDidLoad() self.textField.rac_textSignal().subscribeNext { (x) -> Void in println(x) } let textSignal = self.textField.rac_textSignal().map { (x) -> AnyObject! in NSNumber(bool: ((x as? NSString) ?? "").rangeOfString("@").location != NSNotFound) } //NSNumber (boolean) let colorSignal = textSignal.map { x in ((x as? NSNumber)?.boolValue ?? false) ? UIColor.greenColor() : UIColor.redColor() } // UICOlor //textSignal ~> RAC(button, "enabled") colorSignal ~> RAC(textField, "textColor") let passwordSignal = self.passwordField.rac_textSignal().map { x in NSNumber(bool: (x as? NSString ?? "").length > 4) } //NSNumber let formValidSignal = RACSignal.combineLatest([textSignal, passwordSignal]).map { let tuple = $0 as! RACTuple let bools = tuple.allObjects() as! [Bool] return NSNumber(bool: bools[0] == true && bools[1] == true) } formValidSignal ~> RAC(signInButton, "enabled") button.rac_command = RACCommand(enabled: textSignal, signalBlock: { (x) -> RACSignal! in println("pressed") return RACSignal.empty() }) } }
  • 4.
  • 5. Rx?
  • 7. In computing, reactive programming is a programming paradigm oriented around data flows and the propagation of change. Reactive Programming
  • 8. Functional reactive programming (FRP) is a programming paradigm for reactive programming (asynchronous dataflow programming) using the building blocks of functional programming (e.g. map, reduce, filter). Functional Reactive Programming
  • 9. Functional Reactive Programming functional programming data flows propagation of change
  • 10. Functional Programming 1 부터 10까지 더하는 문제 var sum = 0 for i in 1...10 { sum += 1 } print(sum) Procedural way print((1...10).reduce(0) { $0 + $1 }) Functional way
  • 11. Data Flow (1...10) .filter { $0 % 2 == 0 // 2, 4, 6, 8, 10 } .map { $0 * 10 // 20, 40, 60, 80, 100 } .reduce(0) { $0 + $1 // 300 }
  • 12. Propagation of Change (1...5) .filter { $0 % 2 == 0 // 2, 4 } .map { $0 * 10 // 20, 40 } .reduce(0) { $0 + $1 // 60 }
  • 13. Propagation of Change (1...5) .filter { $0 % 2 == 0 // 2, 4 } .map { $0 * 100 // 200, 400 } .reduce(0) { $0 + $1 // 600 }
  • 14.
  • 16. An API for asynchronous programming with observable streams
  • 17. 단일 다수 동기 Try<T> Iterable<T> 비동기 Future<T> Observable<T>
  • 20. Iterable(pull) Observable(push) 데이터받기 T next() onNext (T) 에러 발견 throws Exception onError(Exception) 완료 !hasNext() onCompleted()
  • 21. Observable.create<String> { observer in observer.onNext("🐶") observer.onNext("🐱") observer.onNext("👽") observer.onCompleted() } .subscribe { print($0) } >> “🐶”..”🐱”.."👽" >>
  • 22.
  • 25.
  • 26. import RxSwift .subscribe { (event) in print(event) } .distinctUntilChanged() 🐶 🐱 👽🐱 🐱🐶 🐶 🐶 👽
  • 27. ["🐶", "🐱", "🐱", "🐶", "👽"].toObservable() import RxSwift .subscribe { (event) in print(event) } .distinctUntilChanged() 🐶 🐱 👽🐱 🐱🐶 🐶 🐶 👽
  • 28. ["🐶", "🐱", "🐱", "🐶", "👽"].toObservable() import RxSwift .subscribe { (event) in print(event) } .distinctUntilChanged() 🐶 🐱 👽🐱 🐱🐶 🐶 🐶 👽🐱 Next(🐶) Next(🐱) Next(🐱) Next(🐶) Next(👽) Completed
  • 29. ["🐶", "🐱", "🐱", "🐶", "👽"].toObservable() import RxSwift .subscribe { (event) in print(event) } .distinctUntilChanged() 🐶 🐱 👽🐱 🐱🐶 🐶 🐶 👽 Next(🐶) Next(🐱) Next(🐶) Next(👽) Completed
  • 30. ["🐶", "🐱", "🐱", "🐶", "👽"].toObservable() import RxSwift .subscribe { (event) in print(event) } .distinctUntilChanged() .addDisposableTo(disposeBag) Disposable
  • 32. ["🐶", "🐱", "🐱", "🐶", "👽"].toObservable() import RxSwift .subscribe { (event) in print(event) } .distinctUntilChanged() .dispose()
  • 33.
  • 34.
  • 35.
  • 36. Creating Observables asObservable, create, deferred, empty, error, toObservable (array), interval, never, just, of, range, repeatElement, timer Transforming Observables buffer, flatMap, flatMapFirst, flatMapLatest, map, scan, window Filtering Observables debounce / throttle, distinctUntilChanged, elementAt, filter, sample, skip, take, takeLast, single Combining Observables merge, startWith, switchLatest, combineLatest, zip Error Handling Operators catch, retry, retryWhen Observable Utility Operators delaySubscription, do / doOnNext, observeOn / observeSingleOn, subscribe, subscribeOn, timeout, using, debug Conditional and Boolean Operators amb, skipWhile, skipUntil, takeUntil, takeWhile Mathematical and Aggregate Operators concat, reduce / aggregate, toArray Connectable Observable Operators multicast, publish, refCount, replay, shareReplay
  • 37. let sequenceThatErrors = Observable<String>.create { observer in observer.onNext("🍎") observer.onNext("🍐") observer.onNext("🍊") if isGoingWrong { observer.onError(Error.Test) print("Error encountered") count += 1 } observer.onNext("🐶") observer.onNext("🐱") observer.onNext("🐭") observer.onCompleted() return NopDisposable.instance } ————result———— 🍎 🍐 🍊 Error encountered sequenceThatErrors .subscribeNext { print($0) } .addDisposableTo(disposeBag) 🍊🍐🍎
  • 38. import UIKit import RxSwift import RxCocoa class EmailLoginViewController: UIViewController { let disposeBag = DisposeBag() @IBOutlet weak var emailTextField: UITextField! @IBOutlet weak var passwordTextField: UITextField! @IBOutlet weak var loginButton: UIButton! … @IBAction func onLogin(sender: UIButton) { guard let email = emailTextField?.text, password = passwordTextField?.text else { return } Router.EmailLogin(["email": email, "password": password]).request .responseJSON { [weak self] response in let json = JSON(response.result.value!) let user = User(json: json) } } // MARK: UIViewController implements override func viewDidLoad() { super.viewDidLoad() } } Login Validator
  • 39. import UIKit import RxSwift import RxCocoa class EmailLoginViewController: UIViewController { let disposeBag = DisposeBag() @IBOutlet weak var emailTextField: UITextField! @IBOutlet weak var passwordTextField: UITextField! @IBOutlet weak var loginButton: UIButton! … @IBAction func onLogin(sender: UIButton) { guard let email = emailTextField?.text, password = passwordTextField?.text else { return } Router.EmailLogin(["email": email, "password": password]).request .responseJSON { [weak self] response in let json = JSON(response.result.value!) let user = User(json: json) self?.succeedToLogin(user) } } // MARK: UIViewController implements override func viewDidLoad() { super.viewDidLoad() } }
  • 40. 1. 이메일형식을 체크 2. 패스워드는 6자리 이상 3. 이메일/패스워드가 비어있을때, 입력을 요구한다.
  • 41. 1. 이메일형식을 체크 2. 패스워드는 6자리 이상 3. 이메일/패스워드가 비어있을때, 입력을 요구한다.
  • 42. emailTextField.rx_text.asObservable() import RxSwift import RxCocoa a@b.c .subscribeNext { print($0) } a a@ a@b a@b. a@b.c .addDisposableTo(disposeBag)
  • 43. emailTextField.rx_text.asObservable() import RxSwift import RxCocoa .subscribeNext { let isValid = $0.isEmail || $0.isEmpty } .addDisposableTo(disposeBag)
  • 44. emailTextField.rx_text.asObservable() import RxSwift import RxCocoa .subscribeNext { let isValid = $0.isEmail || $0.isEmpty } .addDisposableTo(disposeBag)
  • 45. emailTextField.rx_text.asObservable() import RxSwift import RxCocoa .map { $0.isEmail || $0.isEmpty } .addDisposableTo(disposeBag) .subscribeNext { print($0) }
  • 46. emailTextField.rx_text.asObservable() import RxSwift import RxCocoa .map { $0.isEmail || $0.isEmpty } .subscribeNext { self.emailTextField.backgroundColor = $0 ? UIColor.whiteColor() : UIColor.alertColor } .addDisposableTo(disposeBag)
  • 47. 1. 이메일형식을 체크 2. 패스워드는 6자리 이상 3. 이메일/패스워드가 비어있을때, 입력을 요구한다.
  • 48. passwordTextField.rx_text.asObservable() import RxSwift import RxCocoa .map { !(1..<6 ~= $0.characters.count) } .subscribeNext { self.passwordTextField.backgroundColor = $0 ? UIColor.whiteColor() : UIColor.alertColor } .addDisposableTo(disposeBag)
  • 49. 1. 이메일형식을 체크 2. 패스워드는 6자리 이상 3. 이메일/패스워드가 비어있을때, 입력을 요구한다.
  • 50. emailTextField.rx_text.asObservable() import RxSwift import RxCocoa .subscribeNext { let buttonTitle = $0 ? "이메일을 입력하세요" : "로그인 하기" self.loginButton?.setTitle(buttonTitle, forState: .Normal) } .addDisposableTo(disposeBag) .map { $0.isEmpty }
  • 51. passwordTextField.rx_text.asObservable() import RxSwift import RxCocoa .subscribeNext { let buttonTitle = $0 ? "패스워드를 입력하세요" : "로그인 하기" self.loginButton?.setTitle(buttonTitle, forState: .Normal) } .addDisposableTo(disposeBag) .map { $0.isEmpty }
  • 52.
  • 54.
  • 55. let emailEmptyObservable = emailTextField.rx_text.asObservable() .map { $0.isEmpty } let passwordEmptyObservable = passwordTextField.rx_text.asObservable() .map { $0.isEmpty } a a@ a@b a@b.ca@b. .map { $0.isEmpty } true false false false falsefalse “”
  • 56. Observable .combineLatest(emailEmptyObservable, passwordEmptyObservable) { return ($0, $1) } true false false false falsetrue (true, true) (false, true) (false, true) false .combineLatest(email, pass) { return ($0, $1) } (false, false) (false, false)(false, false)
  • 57. let emailEmptyObservable = emailTextField.rx_text.asObservable() .map { $0.isEmpty } let passwordEmptyObservable = passwordTextField.rx_text.asObservable() .map { $0.isEmpty } Observable .combineLatest(emailEmptyObservable, passwordEmptyObservable) { return ($0, $1) } .subscribeNext { tuple in let buttonTitle: String = { switch tuple { case (true, true): return "이메일/패스워드를 입력하세요" case (true, _): return "이메일을 입력하세요" case (_, true): return "패스워드를 입력하세요" default: return "로그인 하기" } }() self.registerButton?.setTitle(buttonTitle, forState: .Normal) self.registerButton?.backgroundColor = tuple.0 || tuple.1 ? UIColor.gray4AColor : UIColor.tintColor } .addDisposableTo(disposeBag)
  • 58.
  • 59.
  • 60. import UIKit import RxSwift import RxCocoa class EmailLoginViewController: UIViewController { let disposeBag = DisposeBag() @IBOutlet weak var emailTextField: UITextField! @IBOutlet weak var passwordTextField: UITextField! @IBOutlet weak var loginButton: UIButton! … // MARK: UIViewController implements override func viewDidLoad() { super.viewDidLoad() addValidations() } func addValidations() { … } }
  • 61. func addValidations() { let emailEmptyObservable = emailTextField.rx_text.asObservable().map { $0.isEmpty } let passwordEmptyObservable = passwordTextField.rx_text.asObservable().map { $0.isEmpty } Observable .combineLatest(emailEmptyObservable, passwordEmptyObservable) { return ($0, $1) } .subscribeNext { tuple in let buttonTitle: String = { switch tuple { case (true, true): return "이메일/패스워드를 입력하세요" case (true, _): return "이메일을 입력하세요" case (_, true): return "패스워드를 입력하세요" default: return "로그인 하기" } }() self.registerButton?.setTitle(buttonTitle, forState: .Normal) self.registerButton?.backgroundColor = tuple.0 || tuple.1 ? UIColor.gray4AColor : UIColor.tintColor } .addDisposableTo(disposeBag) emailTextField.rx_text.asObservable() .map { $0.isEmail || $0.isEmpty } .subscribeNext { self.emailTextField.backgroundColor = $0 ? UIColor.whiteColor() : UIColor.alertColor } .addDisposableTo(disposeBag) passwordTextField.rx_text.asObservable() .map { !(1..<6 ~= $0.characters.count) } .subscribeNext { self.passwordTextField.backgroundColor = $0 ? UIColor.whiteColor() : UIColor.alertColor } .addDisposableTo(disposeBag) }
  • 63. enum Router: URLRequestConvertible { case Collection(Int) var request: Alamofire.Request { return HTTPManager.sharedHTTPManager.request(self) } var method: Alamofire.Method { return .GET } var path: String { switch self { case .Collection(let id): return “/Collections/(id)" } } var parameters: Parameter { switch self { case .Collection: return ["filter": ["include": ["images"]]] } } // MARK: URLRequestConvertible var URLRequest: NSMutableURLRequest { let URL = NSURL(string: Router.baseURLString)! let mutableURLRequest = NSMutableURLRequest(URL: URL.URLByAppendingPathComponent(path)) mutableURLRequest.HTTPMethod = method.rawValue return Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: parameters).0 } } }
  • 64. let collections = Variable([Collection]()) Router.Collections(["filter": filterParameter]).request .validate() .responseJSON { [weak self] response in if let value = response.result.value { let newData = Collection.array(JSON(value)) self?.collections.value = newData return } }
  • 65. extension Alamofire.Request { func rx_validateSuccessfulResponse() -> Request { …… } public func rx_result<T: ResponseSerializerType>( queue queue: dispatch_queue_t? = nil, responseSerializer: T) -> Observable<T.SerializedObject> { return Observable.create { [weak self] observer in self? .rx_validateSuccessfulResponse() .response(queue: queue, responseSerializer: responseSerializer) { _response in switch _response.result { case .Success(let result): if let _ = _response.response { observer.on(.Next(result)) } else { observer.on(.Error(NSError(domain: "Frip", code: -1, userInfo: nil))) } observer.on(.Completed) case .Failure(let error): observer.on(.Error(error as ErrorType)) } } return NopDisposable.instance } } public func rx_JSON(options options: NSJSONReadingOptions = .AllowFragments) -> Observable<AnyObject> { return rx_result(responseSerializer: Request.JSONResponseSerializer(options: options)) } }
  • 66. .response(queue: queue, responseSerializer: responseSerializer) { _response in switch _response.result { case .Success(let result): if let _ = _response.response { observer.on(.Next(result)) } else { observer.on(.Error(NSError(domain: "Frip", code: -1, userInfo: nil))) } observer.on(.Completed) case .Failure(let error): observer.on(.Error(error as ErrorType)) } }
  • 67. let collections = Variable([Collection]()) Router.Collections(["filter": filterParameter]).request .rx_JSON() .retry(1) .startWith([]) .catchErrorJustReturn([]) .bindTo(collections)
  • 68. let collections = Variable([Collection]()) Router.Collections(["filter": filterParameter]).request .rx_JSON() .retry(1) .startWith([]) .catchErrorJustReturn([]) .bindTo(collections) .retry(1)
  • 69. let collections = Variable([Collection]()) Router.Collections(["filter": filterParameter]).request .rx_JSON() .retry(1) .startWith([]) .catchErrorJustReturn([]) .bindTo(collections) .startWith([]) [ ] [Collection, …, Collection]
  • 70. let collections = Variable([Collection]()) Router.Collections(["filter": filterParameter]).request .rx_JSON() .retry(1) .startWith([]) .catchErrorJustReturn([]) .bindTo(collections) .catchErrorJustReturn([]) [ ]
  • 71. let collections = Variable([Collection]()) Router.Collections(["filter": filterParameter]).request .rx_JSON() .retry(1) .startWith([]) .catchErrorJustReturn([]) .bindTo(collections) .bindTo(collections) [ ] […] […] […]
  • 75.
  • 76. https://justhackem.wordpress.com/2015/03/19/rmvvm-architecture/ Reactive MVVM(Model-View-ViewModel) 모바일 응용프로그램 아키텍쳐 https://github.com/devxoul/RxTodo RxTodo