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
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
120
Need For Deliveries
ruiaaperes
0
81
Other Decks in Technology
See All in Technology
JAWS-UGグッズ職人仕事の流儀
kentapapa
0
110
DWH の限界突破! AI エージェント向け爆速リアルタイムデータ基盤 ClickHouse
jozono
1
480
「Docker Desktop不要の時代」は 来たのか?
ueponx
0
770
NDIでApple Vision Proにリアルタイム映像送信
jyouryuusui
0
120
実践! SRE × AI - ABEMA における AIOps -
tetsuya28
8
3.1k
日本語に強いオープンな大規模言語モデル「LLM-jp」
odashi
4
1.1k
Refining Active Record
shugo
0
160
事業成長とデータ活用を止めないためのマネジメントへ挑戦
hiracky16
0
390
分析の民主化を支えるメタデータ整備の実践
kakehashi
PRO
4
1.4k
AI駆動で「他アプリの音を加工できる」アプリを作った
satomasahiro2005
0
150
V8のArray.prototype.flatを最大約20倍速くするまでと、巨大OSSへの大規模コミットの道のり
riyaamemiya
0
290
その Valkey 使いこなしていますか?
onk
PRO
5
1.5k
Featured
See All Featured
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
580
Side Projects
sachag
456
43k
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
550
Embracing the Ebb and Flow
colly
88
5.2k
The Spectacular Lies of Maps
axbom
PRO
1
1.1k
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
780
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
890
Discover your Explorer Soul
emna__ayadi
2
1.3k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
450
Un-Boring Meetings
codingconduct
0
460
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.5k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.6k
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