var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18
Upcoming SlideShare
Loading in...5
×
 

var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18

on

  • 147 views

2014-10-18(土)に開催された「ReactiveCocoa Tokyo #rac_tokyo」の発表資料です。

2014-10-18(土)に開催された「ReactiveCocoa Tokyo #rac_tokyo」の発表資料です。

http://connpass.com/event/8680/

Statistics

Views

Total Views
147
Views on SlideShare
120
Embed Views
27

Actions

Likes
3
Downloads
1
Comments
0

1 Embed 27

https://twitter.com 33

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

var RAC3 = ReactiveCocoa + Swift @ ReactiveCocoa Tokyo #rac_tokyo 10/18 Presentation Transcript

  • 1. var$RAC3$=$Reac,veCocoa$+$Swi2 @ikesyo #rac_tokyo Reac%veCocoa)Tokyo)2014110118)Sat)@freee株式会社
  • 2. @ikesyo いけしょー/池田翔 京都でフリーランスのiOS/Android エンジニアしています 甘いもの大好き!! !!お仕事待ってます!!! 現在フリュー㈱にて 一部RAC3を使ってお仕事中!
  • 3. Reac%veCocoaのコミッター(Contributor)やってます
  • 4. 今日はSwi$ベースになった Reac%veCocoa)3.0のご紹介
  • 5. ※!注意 2014%10%16,(Xcode(6.1(GM(seed(2時点,( swi4%api%reduxブランチ(#1532)の内容に基づきます APIやクラス名など今後変更される可能性は大いにあります ※!実際に7/26の!#rac_kansai!から大きく変わっています……!※
  • 6. RAC$3.0
  • 7. 元々はこれ h"ps://github.com/Reac3veCocoa/ Reac3veCocoa/pull/966
  • 8. _人人人人人人人_ > 突然のSwi$ < ‾Y^Y^Y^Y^Y^Y‾
  • 9. だけではなく RACDC%2014:%June%3rd@Github • The$Future$Of$Reac.veCocoa$by$Jus.n$Spahr9Summers$•$ GitHub$Reac.ve$Cocoa$Developer$Conference • h#p://vimeo.com/98100163 • h#ps://github.com/jspahrsummers/the<future<of< reac>vecocoa
  • 10. h"ps://github.com/jspahrsummers/ RxSwi8 を経て
  • 11. The$Great$Swi,ening$(a.k.a.$the$ new$3.0) h"ps://github.com/Reac3veCocoa/ Reac3veCocoa/pull/1382
  • 12. New$Concepts • Generics)Support • ColdSignal)!)Producer)! • Subscriber)!)Consumer)! • HotSignal)!)Signal)! • ObservableProperty)!)SignalingProperty)! • !)Promise)! • Action
  • 13. Generics(Support 型パラメータは当然サポート public struct ColdSignal<T> {} public final class Subscriber<T>: SinkType {} extension NSNotificationCenter { public func rac_notifications (name: String? = nil, object: AnyObject? = nil) -> HotSignal<NSNotification> } extension NSURLSession { public func rac_dataWithRequest (request: NSURLRequest) -> ColdSignal<(NSData, NSURLResponse)> }
  • 14. ColdSignal • Cold&RACSignal:&Event&Stream • Subscriberをアタッチしてイベントを購読する • Subscriber毎に受け取るイベントやタイミングは異なる • SubscriberがDisposableを持っていて、ColdSignal生成 時のクロージャではDisposableを返さない • subscriber.disposable.addDisposable(...)
  • 15. ColdSignal.swi-public struct ColdSignal<T> { public init(generator: Subscriber<T> -> ()) // +[RACSignal createSignal:] public static func empty() -> ColdSignal // +[RACSignal empty] public static func single(value: T) -> ColdSignal // +[RACSignal return:] public static func error(error: NSError) -> ColdSignal // +[RACSignal error:] public static func never() -> ColdSignal // +[RACSignal never] // -[RACSignal subscribe:] public func subscribe(subscriber: Subscriber<T>) -> Disposable // -[RACSignal subscribeNext:error:completed:] public func subscribe( next: T -> () = doNothing, error: NSError -> () = doNothing, completed: () -> () = doNothing ) -> Disposable }
  • 16. ColdSignalの生成例 extension RACSignal { public func asColdSignal() -> ColdSignal<AnyObject?> { return ColdSignal { subscriber in let next = { (obj: AnyObject?) -> () in subscriber.put(.Next(Box(obj))) } let error = { (maybeError: NSError?) -> () in let nsError = maybeError.orDefault(RACError.Empty.error) subscriber.put(.Error(nsError)) } let completed = { subscriber.put(.Completed) } let disposable: RACDisposable? = self.subscribeNext(next, error: error, completed: completed) subscriber.disposable.addDisposable(disposable) } } }
  • 17. Subscriber • like:'id<RACSubscriber> subscriber • SinkTypeプロトコルのputにEvent<T>でラップした値を渡す • public func put(event: Event<T>) {} • 従来の'-sendNext:'などの代わり • Event<T> -> ()'のクロージャをハンドラー本体として Subscriberを初期化し、ColdSignalのsubscribeに渡せる
  • 18. Subscriber.swi+ public final class Subscriber<T>: SinkType { public typealias Element = Event<T> public let disposable = CompositeDisposable() public init<S: SinkType where S.Element == Event<T>>(_ sink: S) public convenience init(handler: Event<T> -> ()) public convenience init( next: T -> (), error: NSError -> (), completed: () -> ()) public func put(event: Event<T>) }
  • 19. Subscriberの使用例 extension ColdSignal { public func asDeferredRACSignal<U: AnyObject> (evidence: ColdSignal -> ColdSignal<U?>) -> RACSignal { return RACSignal.createSignal { subscriber in let selfDisposable = evidence(self).subscribe(next: { value in subscriber.sendNext(value) }, error: { error in subscriber.sendError(error) }, completed: { subscriber.sendCompleted() }) return RACDisposable { selfDisposable.dispose() } } } }
  • 20. 補足1 • evidenceという型チェックにより、特定の型パラメータを持 つColdSignalでのみメソッドを呼べるように制限 • Objec've)CとのブリッジなのでStructやEnumは渡せず、 AnyObjectでクラスオブジェクトだけに制限 • 使い方:,引数に,identityという関数を渡すだけ
  • 21. Iden%ty.swi, /// The identity function, which returns its argument. /// /// This can be used to prove to the typechecker that a given type A is /// equivalent to a given type B. /// /// For example, the following global function is normally impossible to bring /// into the `Signal<T>` class: /// /// func merge<U>(signal: Signal<Signal<U>>) -> Signal<U> /// /// However, you can work around this restriction using an instance method with /// an “evidence” parameter: /// /// func merge<U>(evidence: Signal<T> -> Signal<Signal<U>>) -> Signal<U> /// /// Which would then be invoked with the identity function, like this: /// /// signal.merge(identity) /// /// This will verify that `signal`, which is nominally `Signal<T>`, is logically /// equivalent to `Signal<Signal<U>>`. If that's not actually the case, a type /// error will result. public func identity<T>(id: T) -> T { return id }
  • 22. 補足2 • 例えばScalaではGeneralized-Type-Constraintsという言語機能で 同様の制限が可能 • h6p://yuroyoro.hatenablog.com/entry/ 20100914/1284471301 • h6p://www.ne.jp/asahi/hishidama/home/tech/scala/ generics.html#hgeneralizedtype_constraints
  • 23. HotSignal • Hot%RACSignal:%Push+driven%stream • CompletedやErrorによる終了はない • T -> ()%のクロージャがオブサーバー%SinkOf<T>%となって observeする • ColdSignalのSubscriberと異なり、全てのオブザーバー が同じイベントを同じタイミングで受け取る
  • 24. HotSignal.swi-public final class HotSignal<T> { public init(_ generator: SinkOf<T> -> ()) public class func never() -> HotSignal public func observe<S: SinkType where S.Element == T> (observer: S) -> Disposable public func observe(next: T -> ()) -> Disposable }
  • 25. HotSignalの生成例 extension NSNotificationCenter { public func rac_notifications (name: String? = nil, object: AnyObject? = nil) -> HotSignal<NSNotification> { let disposable = ScopedDisposable(SerialDisposable()) return HotSignal { sink in let observer = self.addObserverForName(name, object: object, queue: nil) { notification in sink.put(notification) } disposable.innerDisposable.innerDisposable = ActionDisposable { self.removeObserver(observer) } return () } } }
  • 26. HotSignal/Observer(SinkOf<T>)の使用例 extension HotSignal { /// Creates a RACSignal that will forward values from the receiver. /// /// evidence - Used to prove to the typechecker that the receiver is /// a signal of objects. Simply pass in the `identity` function. /// /// Returns an infinite signal that will forward all values from the /// underlying HotSignal. The returned RACSignal will never complete or /// error, so it must be disposed manually. public func asInfiniteRACSignal<U: AnyObject> (evidence: HotSignal -> HotSignal<U?>) -> RACSignal { return RACSignal.createSignal { subscriber in evidence(self).observe { subscriber.sendNext($0) } return nil } } }
  • 27. ObservableProperty • 値の変更をColdSignalとして通知することができるプロパテ ィ用オブジェクト • KVOの代替手段:&Swi*のクラスにはKVOがなく、監視される側 が自分から通知できるように公開するため? • !&func __conversion()&によりラップされた値を透過的に 使用することができる&!&Swi*&1.0でなくなりました!
  • 28. ObservableProperty.swi1 public final class ObservableProperty<T> { public func values() -> ColdSignal<T> // setするとvalues()の戻り値のColdSignalのsubscriberに通知される public var value: T // not public: ミス or 他からの変換? init(_ value: T) /** public func __conversion() -> T public func __conversion() -> Signal<T> */ } extension ObservableProperty: SinkType { public func put(value: T) }
  • 29. ObservablePropertyの使用例 public class Hoge { let name: ObservableProperty<String> = ObservableProperty("nanashi") } public func printName(name: String) { println(name) } let hoge = Hoge() printName(hoge.name.value) // => nanashi hoge.name.values().subscribe(next: { name in println("(name): name was changed!") }) // => nanashi: name was changed! : 最初に現在値が通知される hoge.name.value = "ikesyo" // or hoge.name.put("ikesyo") // by SinkType // => ikesyo: name was changed!
  • 30. !!Promise!! • 単一の値を生成(resolve)する遅延タスクを表現する • ProducerのようなEvent-Streamではないので複数の値を通知 したりはしない • 値は-public let signal: Signal<T?>-でSignalとして参 照できる • resolve前:-nil,-resolve後:-生成された値-を通知
  • 31. Ac#on • RACCommandの置き換え • インプットからアウトプットを返すアクション(主にUI用:&メイ ンスレッドで動作)の実行・結果を提供する • 個別のアクション実行の結果はColdSignal<T>で返す • 結果のチェックは戻り値がColdSignalなのでsubscribeで
  • 32. Ac#on.swi* public final class Action<Input, Output> { // RACCommand.executionSignals相当は現時点でなし public let executing: ColdSignal<Bool> // 実行中かどうか public let enabled: ColdSignal<Bool> // 有効かどうか public let values: HotSignal<Output> // 成功結果 public let errors: HotSignal<NSError> // 失敗結果 // アクションとなるクロージャを渡す public init(enabledIf: HotSignal<Bool>, execute: Input -> ColdSignal<Output>) public func execute(input: Input) -> ColdSignal<Output> // アクションの実行 }
  • 33. おまけ
  • 34. Xcode&6.1,&iOS&7/8両対応で Swi$版のReac)veCocoaを組み込む 方法を共有します。
  • 35. 1. git submodule add https://github.com/ ReactiveCocoa/ReactiveCocoa.git External/ ReactiveCocoa 2. (LlamaKitの微修正……) 3. LlamaKit.framework5/5Reac9veCocoa.framework5をビルドする 4. ビルドしたFrameworkをリンクする 5. Frameworkをアプリにコピーする 6. importして使うだけ!!
  • 36. https://github.com/ikesyo/rac_tokyo_rac3_installation_sample
  • 37. まとめ
  • 38. !!RAC!3.0はまだ早い……!!
  • 39. Q&A?
  • 40. ありがとうございました!