Slide 1

Slide 1 text

ReactiveCocoa and its Recent State @ikesyo Realm meetup #15, 2016-05-27 Fri @Sansan #realm_jp

Slide 2

Slide 2 text

@ikesyo • ͍͚͠ΐʔʗ஑ా ᠳ • ͸ͯͳ@ژ౎ • https://twitter.com/ikesyo • https://github.com/ikesyo

Slide 3

Slide 3 text

✨ Contributions ✨ • ReactiveCocoa • Carthage (Commandant, ReactiveTask) • Result • Himotoki • APIKit

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

Recent State of ReactiveCocoa

Slide 13

Slide 13 text

New Member • @RuiAAPeres Issues • Reduced from around 250 to 80+ (as of 2016-04-26) • 28 issues as of 2016-05-26

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

Moving Rex to the ReactiveCocoa org #2790 1. Discoverability 2. Credibility 3. Expansion 4. Easier to manage

Slide 16

Slide 16 text

Split Objective-C and Swift APIs going forward #2807 Correct me if I'm wrong, but maintaining both an Objective-C and Swift API for RAC is a bit of a burden, right? Perhaps going forward it's worth thinking about slimming ReactiveCocoa down to just support Swift. I'm sure you guys feel the pull of writing things in Swift as much as I do ! Obviously there's a lot of people reliant on the Objective-C APIs (myself included, for some rather large projects) but if there's support for this idea, splitting the language support up into separate repos/projects might be a good first step? What do you think?

Slide 17

Slide 17 text

Remove Objective-C APIs #2830 As discussed in #2807, we will move the Objective-C APIs to a separate repo and also move the Obj-C/Swift bridging to a separate repo. This will need to happen as part of the 5.0 release because it is a breaking change.

Slide 18

Slide 18 text

We are heading to ... • ReactiveCocoa: ReactiveSwift + UI Bindings • ReactiveSwift: Swift only • ReactiveObjC: Objective-C only • ReactiveObjCBridge: Swift <-> ObjC Bridge

Slide 19

Slide 19 text

Community • Community is really important ! • https://github.com/RACCommunity • ReactiveCocoa Community Projects • Inspired by the RxSwift Community • Let's expand the ecosystem! • Slack channel: #reactivecocoa • https://reactivex.slack.com/ • Contact to @ReactiveCocoa if you want to join!

Slide 20

Slide 20 text

Utilities / Examples • RACurated: Curated list of ReactiveCocoa projects • Carthage/Carthage ! • MailOnline/Reactor • ... • RACCommunity/RACNest • inamiy/ReactiveCocoaCatalog

Slide 21

Slide 21 text

Reactive Swift Meetup (2016-04-13) • http://wantedly.connpass.com/event/29039/ • ReactiveCocoaೖ໳ by @Nirma • Getting Started with ReactiveCocoa v4.1.0 by @inamiy • ...

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

Carthage and ReactiveCocoa

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

Streams of Events over time

Slide 26

Slide 26 text

• Create enclosing xcworkspace, add ReactiveCocoa by jspahrsummers · Pull Request #24 · Carthage/Carthage • Create Task module for shelling out by jspahrsummers · Pull Request #25 · Carthage/Carthage • Build project directories using xcodebuild by jspahrsummers · Pull Request #26 · Carthage/Carthage • Update to the new RAC.Swift API by jspahrsummers · Pull Request #31 · Carthage/Carthage • Upgrade dependencies by jspahrsummers · Pull Request #368 · Carthage/Carthage

Slide 27

Slide 27 text

• Promise, ColdSignalͳͲࠓ͸ͳ͖ܕୡ • Signal/SignalProducer΁ͷมભ • Carthageͷ։ൃΛ௨ͯ͠RAC 3.0ͷAPIΛςετɺચ࿅ 1 1 γϯϓϧͳύοέʔδ؅ཧπʔϧ Carthage - Realm is a mobile database: a replacement for SQLite & Core Data

Slide 28

Slide 28 text

ඇಉظॲཧͷఆܕԽ • APIຖʹελΠϧ͕ҟͳͬͯ໎Θͳ͍Α͏ʹ͢Δ • delegate, target-action, callback(Ҿ਺΋༷ʑ), ... • ඇಉظॲཧͷνΣʔϯ • ! Callback Hell • flatMap • flatten ίʔυϕʔεશମͰ࢖͏ͷ͕ޮՌతʢϩοΫΠϯ !ʣ

Slide 29

Slide 29 text

signal.observe { event in switch event { ... } } // observeNext, observeCompleted, ... producer.start { event in switch event { ... } } // startWithNext, startWithCompleted, ... aProducer .flatMap(.Merge) { self.b($0) } .flatMap(.Concat) { self.c($0) } .start(Observer(completed: { ... }, next: { value in ... }))

Slide 30

Slide 30 text

// ReactiveTask public struct Task { public var launchPath: String public var arguments: [String] public var workingDirectoryPath: String? public var environment: [String: String]? public init( _ launchPath: String, arguments: [String] = [], workingDirectoryPath: String? = nil, environment: [String: String]? = nil) { self.launchPath = launchPath self.arguments = arguments self.workingDirectoryPath = workingDirectoryPath self.environment = environment } } public func launchTask( task: Task, standardInput: SignalProducer? = nil ) -> SignalProducer, TaskError>

Slide 31

Slide 31 text

// Tentacle public final class Client { public func releasesInRepository( repository: Repository, page: UInt = 1, perPage: UInt = 30 ) -> SignalProducer<(Response, [Release]), Error> public func releaseForTag( tag: String, inRepository repository: Repository ) -> SignalProducer<(Response, Release), Error> public func downloadAsset( asset: Release.Asset ) -> SignalProducer }

Slide 32

Slide 32 text

ඇಉظॲཧͷఆܕԽ • ಉظతAPI • ςετɺCLIϓϩάϥϜ • RxSwift: RxBlocking // SignalProducer func first() -> Result? func single() -> Result? func last() -> Result? func wait() -> Result<(), Error>

Slide 33

Slide 33 text

// Commandant public protocol CommandType { associatedtype Options: OptionsType associatedtype ClientError: ClientErrorType = Options.ClientError var verb: String { get } var function: String { get } func run(options: Options) -> Result<(), ClientError> }

Slide 34

Slide 34 text

// CopyFrameworks.swift public struct CopyFrameworksCommand: CommandType { public func run(options: NoOptions) -> Result<(), CarthageError> { return inputFiles() .flatMap(.Concat) { frameworkPath -> SignalProducer<(), CarthageError> in let frameworkName = (frameworkPath as NSString).lastPathComponent let source = Result(..) let target = frameworksFolder().map { $0.URLByAppendingPathComponent(frameworkName, isDirectory: true) } return combineLatest( SignalProducer(result: source), SignalProducer(result: target), SignalProducer(result: validArchitectures()) ) .flatMap(.Merge) { (source, target, validArchitectures) -> SignalProducer<(), CarthageError> in let copyFrameworks = copyFramework(...) let copydSYMs = copyDebugSymbolsForFramework(...) return combineLatest(copyFrameworks, copydSYMs) .then(.empty) } } .waitOnCommand() } }

Slide 35

Slide 35 text

ಉظॲཧͷϥοϓ • ಉظॲཧ݁ՌͷϋϯυϦϯά΋ඇಉظॲཧͷ৔߹ͱڞ௨Խ • ಉظͱඇಉظΛҙࣝ͠ͳ͍ • ಺෦ॲཧ͕ಉظ͔ΒඇಉظʹมΘͬͯ΋ݺͼग़͠ଆʹ͸Ө ڹ͕ͳ͍ • ඇಉظॲཧͱͷ߹੒

Slide 36

Slide 36 text

// Project.swift public func loadResolvedCartfile() -> SignalProducer { return SignalProducer.attempt { do { let resolvedCartfileContents = try NSString( contentsOfURL: self.resolvedCartfileURL, encoding: NSUTF8StringEncoding ) return ResolvedCartfile.fromString(resolvedCartfileContents as String) } catch let error as NSError { return .Failure(.ReadFailed(self.resolvedCartfileURL, error)) } } }

Slide 37

Slide 37 text

// Project.swift public func updatedResolvedCartfile... { let resolver = Resolver(...) let resolvedCartfile: SignalProducer resolvedCartfile = loadResolvedCartfile() .map(Optional.init) .flatMapError { _ in .init(value: nil) } return zip(loadCombinedCartfile(), resolvedCartfile) .flatMap(.Merge) { cartfile, resolvedCartfile in return resolver.resolveDependenciesInCartfile( cartfile, lastResolved: resolvedCartfile, dependenciesToUpdate: dependenciesToUpdate ) } .collect() .map(ResolvedCartfile.init) }

Slide 38

Slide 38 text

ܕ෇͚͞ΕͨΤϥʔ • Signal, SignalProducer • Result ͔Βͷੜ੒: attempt, attemptMap • throwsΛѻ͏࣌͸໌നͳܕ΁ͷΩϟετɺ΋͘͠͸NSErrorͱ ͯ͠ѻ͏ʢResultͷAPIʣ • RAC: Atomic, MutablePropertyΛআ͍ͯthrows͸࢖ΘΕ͍ͯͳ ͍ • Carthage: throws͸࢖ΘΕ͍ͯͳ͍

Slide 39

Slide 39 text

// Errors.swift public enum CarthageError: ErrorType, Equatable { ... /// Failed to check out a repository. case RepositoryCheckoutFailed(workingDirectoryURL: NSURL, reason: String, underlyingError: NSError?) /// Failed to read a file or directory at the given URL. case ReadFailed(NSURL, NSError?) /// Failed to write a file or directory at the given URL. case WriteFailed(NSURL, NSError?) ... /// A request to the GitHub API failed. case GitHubAPIRequestFailed(Client.Error) /// An error occurred while shelling out. case TaskError(ReactiveTask.TaskError) }

Slide 40

Slide 40 text

ܕ෇͚͞ΕͨΤϥʔ • Result.NoError: Πϯελϯεੜ੒Ͱ͖ͳ͍Τϥʔܕ • ࣦഊ͢ΔՄೳੑ͕ͳ͍͜ͱΛAPIͷγάωνϟʔͱͯ͠දݱͰ͖ Δ • <~ΦϖϨʔλʔʹΑΔMutableProperty΁ͷSignal, SignalProducerͷόΠϯσΟϯάͷͨΊʹ͸NoErrorͰͳ͚Ε ͹ͳΒͳ͍ 2 2 https://github.com/ReactiveCocoa/ReactiveCocoa/blob/v4.1.0/ReactiveCocoa/Swift/Property.swift#L241-L302

Slide 41

Slide 41 text

// Git.swift internal func branchExistsInRepository(repositoryFileURL: NSURL, pattern: String) -> SignalProducer { return ensureDirectoryExistsAtURL(repositoryFileURL) .succeeded() .flatMap(.Concat) { exists -> SignalProducer in if !exists { return .init(value: false) } return zip( launchGitTask( [ "show-ref", pattern ], repositoryFileURL: repositoryFileURL ).succeeded(), launchGitTask( [ "show-ref", "--tags", pattern ], repositoryFileURL: repositoryFileURL ).succeeded() ) .map { branch, tag in return branch && !tag } } }

Slide 42

Slide 42 text

ࢀߟURL • Visual Identity Refresh for 4.0 · Issue #2190 · ReactiveCocoa/ReactiveCocoa • ReactiveCocoa for a better world • [ON HOLD] ReactiveCocoa 3.0 by jspahrsummers · Pull Request #966 · ReactiveCocoa/ReactiveCocoa • jspahrsummers/RxSwift: Proof-of-concept for implementing Rx primitives in Swift • Release v3.0 · ReactiveCocoa/ReactiveCocoa • Release v4.0 · ReactiveCocoa/ReactiveCocoa • γϯϓϧͳύοέʔδ؅ཧπʔϧ Carthage - Realm is a mobile database: a replacement for SQLite & Core Data • The introduction to Reactive Programming you've been missing • ʲ຋༁ʳ͋ͳ͕ͨٻΊ͍ͯͨϦΞΫςΟϒϓϩάϥϛϯάೖ໳ • RxͷHotͱColdʹ͍ͭͯ - Qiita

Slide 43

Slide 43 text

!" Happy Reactive Coding!! "!

Slide 44

Slide 44 text

Thank you❗"