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
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
110
Need For Deliveries
ruiaaperes
0
80
Other Decks in Technology
See All in Technology
「待ち時間」の消滅と「自我消耗」の加速:生成AI時代のエンジニアを救うメンタル・リソース管理
poropinai1966
0
400
20260801_スクフェス大阪
kgnkhkr
0
460
オートマトンと字句解析でRoslynを読む
tomokusaba
0
130
【CEDEC2026】ゲームシナリオライターを支援するAIツール開発の実践 ― 設計とプロンプトの工夫 ―
cygames
PRO
1
190
最高のシステムプロンプトを作るためにフィードバック機能を導入した話
alchemy1115
1
270
13年運用タイトルのサーバーサイドが辿り着いた現在地 ― モンスターストライクにおける技術・組織・AI活用から得た知見
mixi_engineers
PRO
1
380
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
15
110k
SnowflakeCoCoでデータエンジニアリング!
foursue
0
110
LLMリーダーボードアップデートに向けたAgentic Math_SWEのトレースについて
nejumi
0
190
AWS環境のセキュリティ不安を解消した企業事例 ~よくある課題と対策を一挙公開~
asanoharuki
1
270
plamo-3-translateの開発
pfn
PRO
0
240
【Google Cloud Next Tokyo'26】Gemini Enterprise と Oracle AI Database で実現する、業務データ活用を実現する AI エージェント実装
shisyu_gaku
0
110
Featured
See All Featured
Utilizing Notion as your number one productivity tool
mfonobong
4
490
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
From π to Pie charts
rasagy
0
240
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.5k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
340
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.1k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Building a Scalable Design System with Sketch
lauravandoore
463
34k
How to train your dragon (web standard)
notwaldorf
97
6.7k
The agentic SEO stack - context over prompts
schlessera
0
860
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
62
45k
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