Share
Embed
Transcript
41 slides
-
My twitter avatar shows me casually playing guitar. I got
nice comments when I also used it on Facebook. -
I was actually warming up with a super-simple exercice. (Don't
tell my mom, she was super-proud) -
I started taking lessons a few months ago, I have
a great teacher but to be honest, I'm still not very good at it. ! -
Me, Myself and ReactiveCocoa • I have been using it
for a couple of years, on and off • I'm no expert, but I love the tech, the idea and the community • Ash Furrow said it was okay -
ReactiveCocoa, a history • OpenSourced by the fancy people at
Github in 2012 • Used in Github for Mac, for example • A new version written in swift released (as a beta) a few month ago • (The history is not that important) -
I like to see ReactiveCocoa as a tool to send
stuff through pipes -
In ReactiveCocoa, you play with Signals - (RACSignal *)callWebservice {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSURLSessionDataTask *task = [self.session dataTaskWithURL: url completionHandler:^(...) { // ... }]; [task resume]; return [RACDisposable disposableWithBlock:^{ [task cancel]; }]; }]; } -
In ReactiveCocoa, you play with Signals NSArray *payload = [NSJSONSerialization
JSONObjectWithData: data options: 0 error: nil]; // Some error handling would be nice ! [payload enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL *stop) { [subscriber sendNext: obj]; }]; [subscriber sendCompleted]; -
In ReactiveCocoa, you play with Signals [[client callWebservice] map:^(NSDictionary *payload)
{ return [[FancyObject alloc] initWithDictionary: payload]; }]; -
But things can rapidly get out of hands [[[[client logInUser]
flattenMap:^(User *user) { return [client loadCachedMessagesForUser:user]; }] flattenMap:^(NSArray *messages) { return [client fetchMessagesAfterMessage:messages.lastObject]; }] subscribeNext:^(NSArray *newMessages) { NSLog(@"New messages: %@", newMessages); } completed:^{ NSLog(@"Fetched all messages."); }]; -
ReactiveCocoa and Swift • Rewrote from scratch to benefit from
Swift awesomeness • Strong typing everywhere • Still in beta, use with caution -
Getting started with ReactiveCocoa 3.0 • Drop the framework available
on Github directly in your project • Use Cocoapods • Use Carthage, which uses ReactiveCocoa internally :mindblown.gif: -
Simple example func tick() -> Signal<String, NoError> { var count
= 0 return Signal { sink in NSTimer.schedule(repeatInterval: 1.0) { timer in sendNext(sink, "tick #\(count++)") } return nil } } -
Simple example func fetchCharacterNames() -> SignalProducer<String, NoError> { return SignalProducer
{ observable, disposable in let names = ["Buffy", "Angel", "Spike", "Xander"] for (_, name) in enumerate(names) { sendNext(observable, name) } sendCompleted(observable) } } -
WRONG! ReactiveCocoa 3.0 is a lot more "functional" and map
is actually a function that returns a new signal public func map<T, U, E>(transform: T -> U) -> Signal<T, E> -> Signal<U, E> { // ... } -
If this code makes you feel stupid, join the club
and we'll all get matching tatoos -
Transforming values: using map let charactersSignal = createSignalProducer() let mappedSignal
= map(charactersSignal, { Character(name: $0) }) mappedSignal.start(...) -
Invoking the power of the |> operator createSignalProducer() |> map({
Character(name: $0) }) • Coming from the F# language • Makes your code pretty • Confuses Xcode like nothing before -
More complex (and relevant) example: the Photos framework • Working
on an application that uses the Photos framework • Retrieving the latest photos = callbacksoup -
More complex example: the Photos framework 1. Iterating over a
list of albums 2. For each of these albums, request the assets 3. For each asset, request a UIImage (asynchronously) -
Step 1: Fetching albums func fetchCollections() -> SignalProducer<PHAssetCollection, NoError> {
return SignalProducer { observer, disposable in let fetchOptions = PHFetchOptions() let collections = PHAssetCollection.fetchAssetCollectionsWithType(.SmartAlbum, subtype: .Any, options: fetchOptions) for index in 0..<collections.count { let collection = collections.objectAtIndex(index) as! PHAssetCollection sendNext(observer, collection) } sendCompleted(observer) } } -
Step 1: Fetching collections fetchCollections().start(next: { collection in println(“Collection =
\(collection.localizedTitle)”) }) -
Step 2: Fetching assets in specific collection func fetchAssets(inCollection collection:
PHAssetCollection) -> SignalProducer<PHAsset, NoError> { return SignalProducer { observer, disposable in // We only want the images let assetsOptions = PHFetchOptions() assetsOptions.predicate = NSPredicate(format: “mediaType = %i”, PHAssetMediaType.Image.rawValue) let assets = PHAsset.fetchAssetsInAssetCollection(collection, options: assetsOptions) for assetIndex in 0..<assets.count { sendNext(observer, assets.objectAtIndex(assetIndex) as! PHAsset) } sendCompleted(observer) } } -
Step 3: Fetching thumbnails func fetchImage(forAsset asset: PHAsset) -> SignalProducer<UIImage,
NoError> { return SignalProducer { observer, disposable in let size = CGSize(width: asset.pixelWidth, height: asset.pixelHeight) PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: size, contentMode: .AspectFit, options: PHImageRequestOptions(), resultHandler: { (image, infos) -> Void in sendNext(observer, image) sendCompleted(observer) }) } } -
Step 4: Merging all the things func fetchLatestScreenshot() -> SignalProducer<UIImage,
NoError> { return fetchCollections() |> flatMap(.Merge, { collection in return fetchAssets(inCollection: collection) |> flatMap(.Latest, { asset in return fetchImage(forAsset: asset) }) }) } -
flatMap is a common concept in functional programing • Apply
a function that returns a sequence for each element in the "pipe" • Here it applies a function to every collection and returns a sequence of assets -
Bonus: Filtering assets // ... fetchAssets(inCollection: collection) |> filter({ asset
in let size = CGSize(width: asset.pixelWidth, height: asset.pixelHeight) return find(resolutions, size) != nil }) // ... -
Conclusion • ReactiveCocoa is a great tool, even if it
sounds confusing your app can benefit from it • Xcode will be confused a lot, it makes the development suspensefull • There is a lot I haven't covered (observing properties...) • Questions? -
Thanks! 1. Picture by the awesome @Misszonzonnette 2. Simple tick
example Shamelessly borrowed from http:// blog.scottlogic.com 3. We're hiring at Mirego!