Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Real World ReactiveCocoa ❤️
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
R. Peres
April 24, 2015
Technology
260
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Real World ReactiveCocoa ❤️
R. Peres
April 24, 2015
More Decks by R. Peres
See All by R. Peres
diff objetive-c swift
ruiaaperes
0
110
Need For Deliveries
ruiaaperes
0
81
Other Decks in Technology
See All in Technology
人間はどの意思決定を手放せるのか
kawasima
14
6.8k
20260912_スクフェス三河
kgnkhkr
0
380
10分で知る最近のOmarchy
komagata
0
320
研究開発部の紹介 / Sansan R&D Profile
sansan33
PRO
5
25k
アクセスキーこわい やめかたと漏らさない工夫
sassssan68
1
230
空間オーディオで過去の 自分(ゴースト)と競うランニング 〜HealthKitのルートを足音に変える実装〜
nao_randd
0
220
LTのテーマ どうきめてる?〜5つの型と私のやり方〜
yama3133
1
100
20260912_スクラムにジェネラリストは必要か
ryugen04
0
420
目の前の楽しいが人生を変える - コミュニティの螺旋の歩き方と楽しむコツ / change your life
soudai
PRO
4
600
10Xに技術的負債をもたらした「2つの境界の歪み」その構造と解消への営み
10xinc
0
1.9k
LLMに渡さなかった仕事
nanaism
0
170
2026/09/10 Spring Bootから Jakarta EE/MicroProfileへの移行
megascus
0
370
Featured
See All Featured
Fashionably flexible responsive web design (full day workshop)
malarkey
409
67k
SEO for Brand Visibility & Recognition
aleyda
0
4.7k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
840
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
YesSQL, Process and Tooling at Scale
rocio
174
15k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
The Curious Case for Waylosing
cassininazir
1
510
Leo the Paperboy
mayatellez
10
2.3k
[RailsConf 2023] Rails as a piece of cake
palkan
59
7k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
The Spectacular Lies of Maps
axbom
PRO
1
990
Ruling the World: When Life Gets Gamed
codingconduct
0
330
Transcript
ReactiveCocoa @RuiAAPeres Real World
101 Signals
[RACObserve(self, usernameTextField) subscribeNext:^(NSString *newName) { NSLog(@"%@", newName); }]; Subscribers
Higher Order functions [[RACObserve(self, usernameTextField) filter:^(NSString *newName) { return [newName
hasPrefix:@"j"]; }] subscribeNext:^(NSString *newName) { NSLog(@"%@", newName); }];
Bind + Derivation RAC(self, loginButton.enabled) = [RACSignal combineLatest: combinedSignals reduce:^(NSString
*p, NSString *u) { return @(p.length > 0 && u.length > 0); }]; NSArray *combinedSignals = @[RACObserve(self, passwordTextField), RACObserve(self, usernameTextField)];
Composition [[[loginUserSignal flattenMap:^(User *user) { // Return a signal that
loads cached messages for the user. return [client loadCachedMessagesForUser:user]; }] flattenMap:^(NSArray *messages) { // Return a signal that fetches any remaining messages. return [client fetchMessagesAfterMessage:messages.lastObject]; }] subscribeNext:^(NSArray *newMessages) { NSLog(@"New messages: %@", newMessages); } completed:^{ NSLog(@"Fetched all messages."); }];
“The power of these abstractions are very hard to convey
to someone who has never had the privilege of learning them” Bartosz Milewski
None
ViewModel DataSource Storage
ViewModel
@interface RPNotificationsViewModel : NSObject @property(nonatomic,strong,readonly)RACCommand *notificationsCommand; @property(nonatomic,strong,readonly)RACSignal *errorMessageSignal; @property(nonatomic,strong,readonly)RACSignal *notificationsSignal;
@end
DataSource
@interface RPNotificationsDataSource : NSObject @property(nonatomic,strong,readonly)RACSignal *dataSourceChanged; - (instancetype)initWithNotificationsSignal:(RACSignal *)signal; -
(NSString *)titleForSection:(NSUInteger)index; @end
self.dataSourceChanged = [signal map:^id(NSArray *notifications) { NSArray *normalizedNotifications = //
special sauce return normalizedNotifications; }];
@[OCTNotification1, OCTNotification2, OCTNotification3…]; Map from an Array to a NSOrderedSet
fold @[“RuiPeres/Octify, iOS-Goodies/iOS-Goodies, ReactiveCocoa/ReactiveCocoa];
@“ReactiveCocoa/ReactiveCocoa” @“RuiAAPeres/Octify” @“iOS-Goodies/iOS-Goodies” [[signal map:^id(NSArray *notifications) { }]; @property(nonatomic,strong)NSOrderedSet *sections;
return [NSOrderedSet orderedSetWithArray: ]; RAC(self,sections) = [notifications.rac_sequence foldLeftWithStart:[NSMutableOrderedSet orderedSet] reduce:^id(NSMutableOrderedSet *accumulator, OCTResponse *response) { OCTNotification *notification = response.parsedResult; [accumulator addObject:[notification ownerAndLogin]]; return accumulator; }].array
Storage
@interface RPNotificationsStorage : NSObject + (RACSignal *)storeNotifications:(RACSignal *)signal; + (RACSignal
*)storedNotifications; @end
+ (RACSignal *)storeNotifications:(RACSignal *)signal { return [signal doNext:^(NSArray *notifications) {
// Store the notifications }]; }
+ (RACSignal *)storedNotifications { return [RACSignal createSignal: ^RACDisposable *(id<RACSubscriber> subscriber)
{ NSError *error = // if something fails NSArray *notifications = // get notifications if (error) { [subscriber sendError:[NSError storedError]]; } else { [subscriber sendNext:notifications]; [subscriber sendCompleted]; } return nil; }]; }
The okay way
VM subscribed by VC DS UI ST
[self.notificationsViewModel.notificationsSignal subscribeNext:^(NSArray *notifications){ // 1. Store the notifications // 2.
Update the Data Source // 3. Update the UI }];
“We can do better”
VM DS Observed + Bind Network -> DataSource
notifications = self.notificationsViewModel.notificationsSignal; dataSource = [[RPNotificationsDataSource alloc] initWithNotificationsSignal:notifications];
VM ST injected side effect DS Observed + Bind Network
+ Storage -> DataSource
notifications = self.notificationsViewModel.notificationsSignal; persistence = [RPNotificationsPersistence storeNotifications:notifications]; dataSource = [[RPNotificationsDataSource
alloc] initWithNotificationsSignal:persistence];
ST DS Observed + Bind Storage -> DataSource
persistence = [RPNotificationsPersistence storedNotifications]; dataSource = [[RPNotificationsDataSource alloc] initWithNotificationsSignal:persistence];
DS UI Observed + Bind Observed + Bind UI
RAC(self,nyanCat.hidden) = [self.dataSource.dataSourceChanged map:^id(NSArray *notifications) { return [notifications count] ==
0?@YES:@NO; }];
RAC([UIApplication sharedApplication],applicationIconBadgeNumber) = [[self.dataSource.dataSourceChanged filter:^BOOL(id value) { return [RPPreferences preference:RPBadgeCountPreference];
}] map:^id(NSArray *notifications) { return @([notifications count]); }];
VM ST side effect DS Observed + Bind UI Observed
+ Bind Observed + Bind UI
None
RACSequence *handlers = @[ @"twitter://user?screen_name=%@", @"tweetbot://%@/user_profile/%@", @"twitterrific:///profile?screen_name=%@", @“https://twitter.com/%@"].rac_sequence; return [[[[handlers
map:^id(NSString *value) { return [NSString stringWithFormat:value,screenName,screenName]; }] map:^id(NSString *value) { return [NSURL URLWithString:value]; }] filter:^BOOL(NSURL *value) { return [[UIApplication sharedApplication] canOpenURL:value]; }] head];
Final thoughts
Thanks! @RuiAAPeres