Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
RACDC – RACify
Search
Dave Lee
September 09, 2014
Programming
1
160
RACDC – RACify
A run through examples of building ReactiveCocoa APIs out of traditional objective-c APIs.
Dave Lee
September 09, 2014
Tweet
Share
More Decks by Dave Lee
See All by Dave Lee
Advanced Debugging & Swift
kastiglione
2
690
Other Decks in Programming
See All in Programming
React 19でお手軽にCSS-in-JSを自作する
yukukotani
5
570
Swiftコンパイラ超入門+async関数の仕組み
shiz
0
180
functionalなアプローチで動的要素を排除する
ryopeko
1
240
Jaspr Dart Web Framework 박제창 @Devfest 2024
itsmedreamwalker
0
150
PicoRubyと暮らす、シェアハウスハック
ryosk7
0
230
2025.01.17_Sansan × DMM.swift
riofujimon
2
570
AWSのLambdaで PHPを動かす選択肢
rinchoku
2
390
Rubyでつくるパケットキャプチャツール
ydah
0
180
Асинхронность неизбежна: как мы проектировали сервис уведомлений
lamodatech
0
1.4k
20241217 競争力強化とビジネス価値創出への挑戦:モノタロウのシステムモダナイズ、開発組織の進化と今後の展望
monotaro
PRO
0
290
PHPカンファレンス 2024|共創を加速するための若手の技術挑戦
weddingpark
0
140
月刊 競技プログラミングをお仕事に役立てるには
terryu16
1
1.2k
Featured
See All Featured
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
7
570
Designing for humans not robots
tammielis
250
25k
Practical Orchestrator
shlominoach
186
10k
Agile that works and the tools we love
rasmusluckow
328
21k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
226
22k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
Building Better People: How to give real-time feedback that sticks.
wjessup
366
19k
Product Roadmaps are Hard
iamctodd
PRO
50
11k
For a Future-Friendly Web
brad_frost
176
9.5k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
Speed Design
sergeychernyshev
25
740
How to Ace a Technical Interview
jacobian
276
23k
Transcript
RACify Dave Lee @kastiglione RACDC 2014
RACSignalify
Stealth Signals • Blocks • Delegates • Notifications • Errors
• Target-Action • KVO • Method Overriding
Bridging the Gap • +[RACSignal defer:] • -‐[NSNotificationCenter rac_addObserverForName:object:]
• -‐[NSObject rac_signalForSelector:] • +[RACSignal createSignal:] • RACObserve()
[RACSignal new]
[RACSignal return:value]
[RACSignal error:error]
[RACSignal empty]
[RACSubject subject]
+[RACSignal defer:] [RACSignal defer:^{ return [RACSignal return:@(arc4random())];
}]
+[RACSignal defer:] [RACSignal defer:^{ // Perform per-‐subscription side
effects. u_int32_t r = arc4random(); ! // Start (and in this case complete) the signal. return [RACSignal return:@(r)]; }]
+[RACSignal createSignal:] [RACSignal createSignal:^(id<RACSubscriber subscriber) { // Perform
per-‐subscription side effects. u_int32_t r = arc4random(); ! // Start (and in this case complete) the signal. [subscriber sendNext:@(r)]; [subscriber sendCompleted]; ! return (RACDisposable *)nil; }]
+[RACSignal createSignal:] [RACSignal createSignal:^(id<RACSubscriber subscriber) { return (RACDisposable
*)nil; }] [RACSignal empty]
AFNetworking
AFHTTPRequestOperationManager *manager = …; [manager GET:URLString parameters:params
success:^(AFHTTPRequestOperation *op, id response) { // Success-‐y } failure:^(AFHTTPRequestOperation *op, NSError *e) { // Fail-‐y }];
[RACSignal createSignal:^(id<RACSubscriber subscriber) { [manager GET:URLString parameters:params
success:^(AFHTTPRequestOperation *op, id response) { [subscriber sendNext:response]; [subscriber sendCompleted]; } failure:^(AFHTTPRequestOperation *op, NSError *e) { [subscriber sendError:e]; }]; }]
[RACSignal createSignal:^(id<RACSubscriber subscriber) { NSOperation *operation = [manager
GET:URLString parameters:params success:^(AFHTTPRequestOperation *op, id response) { [subscriber sendNext:response]; [subscriber sendCompleted]; } failure:^(AFHTTPRequestOperation *op, NSError *e) { [subscriber sendError:e]; }]; ! return [RACDisposable disposableWithBlock:^{ [operation cancel]; }]; }]
Core Data
__block NSArray *results; [managedObjectContext performBlock:^{ NSError *error;
results = [managedObjectContext executeFetchRequest:fetchRequest error:&error]; }];
[RACSignal createSignal:^(id<RACSubscriber> subscriber) { RACDisposable *disposable = [RACDisposable
new]; ! [managedObjectContext performBlock:^{ if (disposable.disposed) return; ! NSError *error; NSArray *results = [managedObjectContext performFetch:fetchRequest error:&error]; ! if (results != nil) { [subscriber sendNext:results]; [subscriber sendCompleted]; } else { [subscriber sendError:error]; } }];
! [managedObjectContext performBlock:^{ if (disposable.disposed) return;
! NSError *error; NSArray *results = [managedObjectContext performFetch:fetchRequest error:&error]; ! if (results != nil) { [subscriber sendNext:results]; [subscriber sendCompleted]; } else { [subscriber sendError:error]; } }]; ! return disposable; }];
Core Location
CLLocationManager *locationManager = … locationManager.delegate = self; static
volatile int32_t subscriberCount = 0;
[RACSignal createSignal:^(id<RACSubscriber> subscriber) { RACSignal *locations = [[self
rac_signalForSelector:@selector(…didUpdateLocations:) fromProtocol:@protocol(CLLocationManagerDelegate)] reduceEach:^(id _,NSArray *locations) { return locations; }]; ! RACSignal *error = [[[[self rac_signalForSelector:@selector(…didFailWithError:) fromProtocol:@protocol(CLLocationManagerDelegate)] reduceEach:^(id _, NSError *error) { return error; }] filter:^ BOOL (NSError *error) { // Documentation says Core Location will keep // will keep trying after kCLErrorLocationUnknown. return error.code != kCLErrorLocationUnknown;
RACSignal *error = [[[[self rac_signalForSelector:@selector(…didFailWithError:)
fromProtocol:@protocol(CLLocationManagerDelegate)] reduceEach:^(id _, NSError *error) { return error; }] filter:^ BOOL (NSError *error) { // Documentation says Core Location will keep // will keep trying after kCLErrorLocationUnknown. return error.code != kCLErrorLocationUnknown; }] flattenMap:^(NSError *error) { return [RACSignal error:error]; }]; ! RACDisposable *disposable = [[RACSignal merge:@[ locations, error ]] subscribe:subscriber];
RACDisposable *disposable = [[RACSignal
merge:@[ locations, error ]] subscribe:subscriber]; ! if (OSAtomictIncrement32(&subscriberCount) == 1) { [locationManager startUpdatingLocation]; } else { [subscriber sendNext:locationManager.location]; } ! return [RACDisposable disposableWithBlock:^{ [disposable dispose]; if (OSAtomictDecrement32(&subscriberCount) == 0) { [locationManager stopUpdatingLocation]; } }]; }];
AFNetworking
! RACSignal *isReachable = [RACObserve( reachabilityManager, networkReachabilityStatus)
map:^(NSNumber *networkReachabilityStatus) { switch (networkReachabilityStatus.intValue) { case AFNetworkReachabilityStatusReachableViaWWAN: case AFNetworkReachabilityStatusReachableViaWiFi: return @YES; } return @NO; }];
Notifications
UIApplicationWillEnterForegroundNotification UIApplicationDidEnterBackgroundNotification UIApplicationWillResignActiveNotification UIApplicationDidBecomeActiveNotification
RACSignal *isForeground = [RACSignal merge:@[ [[defaultCenter
rac_addObserverForName:WillEnterForeground …] mapReplace:@YES] [[defaultCenter rac_addObserverForName:DidEnterBackground …] mapReplace:@NO] ]]; ! RACSignal *hasLaunchedActive = [RACSignal if:isForeground then:[[defaultCenter rac_addObserverForName:DidBecomeActive …] take:1] else:[RACSignal empty]];
More… • Use -‐rac_signalForSelector:, everywhere. • Check out the AppKit
and UIKit extensions in RAC