
ReactiveCocoaã®åŠç¿ãå§ããã°ããã®ãšãããããäœã§ãããããããŸããã§ããã ããªã¢ã¯ãã£ããã¯ãšãŠãã¯ãŒã«ã«èããããæ©èœçãã¯ã¹ããŒãã«èãããŸãã ããããReactive Cocoaãæã«å ¥ããããšããèªæã«è² ããåŸãããã䜿ããã«ã³ãŒããæžãããšã¯ãã¯ãæ³åã§ããŸããã
ReactiveCocoaã¯ãæ©èœçãªã¢ã¯ãã£ãããã°ã©ãã³ã°ã®äžçãžã®çªãéããã¬ãŒã ã¯ãŒã¯ã§ãã ããã«ãããFRPã®è©³çŽ°ãªçè«çç¥èãå¿ èŠãšããã«ããã®ãã©ãã€ã ã®å®çšåããå©çãåŸãããšãã§ããŸãã
å®éã®ãããžã§ã¯ãã§ReactiveCocoaãç¿åŸããããã€ãã®ç°¡åãªããšãè¡ããŸããããŸãããã®èšäºã§èª¬æãã2ã€ã®åé¡ã解決ããããã«ããã䜿çšããŸããã ãã¬ãŒã ã¯ãŒã¯ã®å®çšçãªç解ãåŸãããšãã§ããããã«ããæ¹æ³ãã§ã¯ãªããäœããã¹ããããšèšããŸãã
1.ã³ãã¥ãã±ãŒã·ã§ã³
ReactiveCocoaã§ã®çœ²åã¯éåžžãæ¥ç¶ããå§ãŸããŸãã çµå±ã®ãšããããããã¯åå¿è ãç解ã§ããæãç°¡åãªãã®ã§ãã
é¢ä¿ã ãã§ã¯ãObjective-Cã®æ¢åã®KVOã¡ã«ããºã ãè£å®ããã ãã§ãã ReactiveCocoaãKVOã«ããããæ°ããæ©èœã¯ãããŸããïŒ ãã®ãã䟿å©ãªã€ã³ã¿ãŒãã§ã€ã¹ã¯ãã¢ãã«ã®ç¶æ ãšUIã®ç¶æ ã宣èšã¹ã¿ã€ã«ã§ãã€ã³ãããããã®ã«ãŒã«ãèšè¿°ããæ©èœãè¿œå ããŸãã
ããŒãã«ã»ã«ã®äŸã䜿çšããŠé¢ä¿ãèŠãŠã¿ãŸãããã
éåžžãã»ã«ã¯ã¢ãã«ã«æ¥ç¶ããããã®èŠèŠçç¶æ ïŒãŸãã¯MVVMã¢ããã¢ã¬ã³ãã®å Žåã¯ViewModelç¶æ ïŒã衚瀺ããŸãã ReactiveCocoaã¯å€ãã®å ŽåMVVMãšåãã³ã³ããã¹ãã§è¡šç€ºãããŸããããã®éãåæ§ã§ãã ã³ãã¥ãã±ãŒã·ã§ã³ã¯ããªãã®äººçã楜ã«ããããã®æ段ã«éããŸããã
- (void)awakeFromNib { [super awakeFromNib]; RAC(self, titleLabel.text) = RACObserve(self, model.title); }
ããã¯å®£èšçãªã¹ã¿ã€ã«ã§ãã ãã©ãã«ã®ããã¹ããåžžã«ã¢ãã«ã®ã¿ã€ãã«å€ã«çãããããã --awakeFromNibã¡ãœããå ã ã¿ã€ãã«ãã¢ãã«ããã€å€æŽããããã¯åé¡ã§ã¯ãããŸããã
ãããå éšçã«ã©ã®ããã«æ©èœããããèŠããšã RACObserveã¯ãã¹ïŒãã®äŸã§ã¯èªå·±ãªããžã§ã¯ããã " mode.title "ïŒãååŸãããããRACSignalã«å€æãããã¯ãã§ããããšãããããŸãã RACSignalã¯ãReactiveCocoaãã¬ãŒã ã¯ãŒã¯ã®ãªããžã§ã¯ãã§ãããå°æ¥ã®ããŒã¿ãè¡šããæäŸããŸãã ãã®äŸã§ã¯ã ã¿ã€ãã«ãŸãã¯ã¢ãã«ãå€æŽããããã³ã«ãã model.title ãããããŒã¿ãé ä¿¡ããŸãã
ãã®æ®µéã§ã¯è©³çŽ°ã«ç«ã¡å ¥ãå¿ èŠããªããããä¿¡å·ã«ã€ããŠã¯åŸã§èª¬æããŸãã çŸåšãã¢ãã«ã®ç¶æ ãã€ã³ã¿ãŒãã§ã€ã¹ã«åã«ããªã³ã¯ãããŠãçµæã楜ããããšãã§ããŸãã
å€ãã®å Žåãã¢ãã«ã®ç¶æ ãå€æããŠUIã«è¡šç€ºããå¿ èŠããããŸãã ãã®å Žåã -mapæŒç®åã䜿çšã§ããŸãã
RAC(self, titleLable.text) = [RACObserve(self, model.title) map:^id(NSString *text) { return [NSString stringWithFormat:@âtitle: %@â, text]; }]
UIã䜿çšãããã¹ãŠã®æäœã¯ã ã¡ã€ã³ã¹ã¬ããã§å®è¡ããå¿ èŠããããŸã ã ãã ããããšãã°ã ã¿ã€ãã«ãã£ãŒã«ãã¯ããã¯ã°ã©ãŠã³ãã¹ã¬ããã§å€æŽã§ããŸãïŒããŒã¿ãåŠçãããšããªã©ïŒã æ°ããã¿ã€ãã«ã®å€ãã¡ã€ã³ã¹ããªãŒã ã§ãµãã¹ã¯ã©ã€ããŒã«é ä¿¡ããããã«è¿œå ããå¿ èŠããããã®ã¯æ¬¡ã®ãšããã§ãã
RAC(self, titleLabel.text) = [RACObserve(self, model.title) deliverOnMainThread];
RACObserveã¯æ¡åŒµãã¯ã-rac_valuesForKeyPathïŒãªãã¶ãŒããŒïŒããããããã«ããªãã¯ããããŸã-ãã®ãã¯ãã¯åžžã«èªåããªãã¶ãŒããŒãšããŠãã£ããã£ããŸãã ãããã¯å ã§RACObserveã䜿çšããå Žåã¯ããªã³ã¯ãµã€ã¯ãªã³ã°ãäœæããã匱ããªã³ã¯ã䜿çšããããã«ããŠãã ããã ReactiveCocoaã«ã¯ããããã®ããŒãºã«å¯Ÿå¿ãã䟿å©ãª@weakifyããã³@strongifyãã¯ãããããŸãã
æ¥ç¶ã«ã€ããŠæ³šæããå¿ èŠããããã1ã€ã®è©³çŽ°ã¯ãã¢ãã«ã®ç¶æ ãããŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ã®éèŠãªå€æŽããã¢ãã«ã®ç¶æ ã®é »ç¹ãªå€æŽã«é¢é£ä»ããããŠããå Žåã§ãã ããã¯ãã¢ããªã±ãŒã·ã§ã³ã®ããã©ãŒãã³ã¹ã«æªåœ±é¿ãäžããå¯èœæ§ããããŸãããããåé¿ããã«ã¯ã -throttleæŒç®åã䜿çšã§ããŸãã - NSTimeIntervalãåãå ¥ããæå®ããæéééåŸã«ãµãã¹ã¯ã©ã€ãã«ã次ã®ãã³ãã³ããéä¿¡ããŸãã
2.ã³ã¬ã¯ã·ã§ã³ã®æäœïŒãã£ã«ã¿ãŒãããããåæžïŒ
ååäœæ¥ã¯ãReactiveCocoaã§æ¬¡ã«æ€èšãããã®ã§ããã é åã®æäœã«ã¯æéãããããŸãããïŒ ã¢ããªã±ãŒã·ã§ã³ã®å®è¡äžã«ããããã¯ãŒã¯ããããŒã¿é åãå±ããå¿ èŠãªåœ¢åŒã§ãŠãŒã¶ãŒã«è¡šç€ºã§ããããã«å€æŽããå¿ èŠããããŸãã
ãããã¯ãŒã¯ããã®çããŒã¿ã¯ããªããžã§ã¯ããŸãã¯ãã¥ãŒã¢ãã«ã«å€æããããŠãŒã¶ãŒã«è¡šç€ºãããå¿ èŠããããŸãã
ReactiveCocoaã§ã¯ãã³ã¬ã¯ã·ã§ã³ã¯RACSequenceã¯ã©ã¹ãšããŠè¡šãããŸãã Cocoaã³ã¬ã¯ã·ã§ã³ãReactiveCocoaã³ã¬ã¯ã·ã§ã³ã«å€æãããã¹ãŠã®ã¿ã€ãã®Cocoaã³ã¬ã¯ã·ã§ã³ã«ã¯ã«ããŽãªããããŸãã ãããã®å€æåŸã mapãfilterãreduceãªã©ã®ããã€ãã®æ©èœã¡ãœãããååŸããŸãã
以äžã«å°ããªäŸã瀺ããŸãã
RACSequence *sequence = [[[matchesViewModels rac_sequence] filter:^BOOL(MatchViewModel *match) { return [match hasMessages]; }] map:^id(MatchViewModel *match) { return match.chatViewModel; }];
ãŸãããã¥ãŒã¢ãã«ããã£ã«ã¿ãŒåŠçããŠãæ¢ã«ã¡ãã»ãŒãžãæã£ãŠãããã®ãéžæããŸãïŒ -ïŒBOOLïŒhasMessages ïŒã ãã®åŸãããããä»ã®ãã¥ãŒã¢ãã«ã«å€æããå¿ èŠããããŸãã
ã·ãŒã±ã³ã¹ãå®äºããããNSArrayã«å€æãçŽãããšãã§ããŸãã
NSArray *chatsViewModels = [sequence array];
ããäžåºŠ-mapïŒæŒç®åã䜿çšããŠããããšã«æ°ã¥ããŸãããïŒ ãã ããä»åã¯ããªã³ã¯ã®å Žåã®ããã«ã RACSignalã§ã¯ãªãRACSequenceã«é©çšãããŸãã
RACã¢ãŒããã¯ãã£ã®çŽ æŽããããšããã¯ã RACSignalãšRACSequenceã® 2ã€ã®äž»èŠãªã¯ã©ã¹ãããªãã芪ã¯ã©ã¹ã1ã€ã§ããRACStreamã§ãããšããããšã§ã ã ã¹ããªãŒã å šäœãšä¿¡å·ã¯ãã¹ããªãŒã ãåãããŠããããã·ã¥ã§ãïŒæ°ããå€ã¯ãµãã¹ã¯ã©ã€ããŒã«ããã·ã¥ãããŠè¡šç€ºã§ããŸããïŒãã·ãŒã±ã³ã¹ã¯æ ŒçŽåŒã¹ããªãŒã ãã©ã€ãã§ãïŒèª°ããèŠæ±ãããšãã«å€ãæäŸããŸãïŒã
泚ç®ã«å€ãããã1ã€ã®ããšã¯ããªãã¬ãŒã·ã§ã³ããªã³ã¯ããæ¹æ³ã§ãã ããã¯RACã®éèŠãªæŠå¿µã§ããã RACSignalããã³RACSequenceã§ã䜿çšãããŸãã
3.ãããã¯ãŒãã³ã°
ãã¬ãŒã ã¯ãŒã¯ã®æ©èœãç解ããããã®æ¬¡ã®ã¹ãããã¯ãããã䜿çšããŠãããã¯ãŒã¯ã§äœæ¥ããããšã§ãã é¢ä¿ã«ã€ããŠè©±ããŠãããšãã«ãMarcos RACObserveãRACSignalãäœæããããšãèšåããŸãããããã¯ãå°æ¥é ä¿¡ãããããŒã¿ãè¡šããŸãã ãã®ãªããžã§ã¯ãã¯ããããã¯ãŒã¯èŠæ±ãæ瀺ããã®ã«çæ³çã§ãã
ã·ã°ãã«ã¯3çš®é¡ã®ã€ãã³ããéä¿¡ããŸãã
- next-å°æ¥ã®äŸ¡å€/䟡å€;
- ãšã©ãŒ -NSError *å€ãä¿¡å·ãæ£åžžã«å®äºã§ããªãããšãæå³ããŸãã
- completed-ã·ã°ãã«ãæ£åžžã«å®äºããããšãæå³ããŸãã
ã·ã°ãã«ã®èçšå¹Žæ°ã¯ãä»»æã®æ°ã®æ¬¡ã®ã€ãã³ãã§æ§æããã1ã€ã®ãšã©ãŒãŸãã¯å®äº ïŒãã ããäž¡æ¹ã§ã¯ãããŸããïŒã
ããã¯ããããã¯ã䜿çšããŠãããã¯ãŒã¯èŠæ±ãäœæããæ¹æ³ãšéåžžã«äŒŒãŠããŸãã ããããéãã¯äœã§ããïŒ åŸæ¥ã®ãããã¯ãä¿¡å·ã§çœ®ãæããçç± ããã€ãã®çç±ããããŸãã
1ïŒã³ãŒã«ããã¯ãåãé€ããŸãïŒ
ãã®æªå€¢ã®ã³ãŒãã¯ãè€æ°ã®ãµãã¯ãšãªããããåŸç¶ã®ãµãã¯ãšãªãããããåã®ãµãã¯ãšãªã®çµæã䜿çšããå Žåã«çºçããŸãã
2ïŒãšã©ãŒã1ãæã§åŠçããŸãã
以äžã«å°ããªäŸã瀺ããŸãã
loginUserãšfetchUserInfoã® 2ã€ã®ã·ã°ãã«ããããšããŸãã ãŠãŒã¶ãŒã«ããã°ã€ã³ãããŠããããŒã¿ãåä¿¡ããã·ã°ãã«ãäœæããŸãããã
RACSignal *signal = [[networkClient loginUser] flattenMap:^RACStream *(User *user) { return [networkClient fetchUserInfo:user]; }];
loginUserä¿¡å·ã次ã®ã€ãã³ããéä¿¡ãããšã flattenMapãããã¯ãåŒã³åºããããã®å€ã¯ãŠãŒã¶ãŒãã©ã¡ãŒã¿ãŒãä»ããŠãããã¯ã«æž¡ãããŸãã flattenMapãããã¯ã§ã¯ãåã®ä¿¡å·ãããã®å€ãååŸããçµæãšããŠæ°ããä¿¡å·ãçæããŸãã ããã§ã¯ããã®ã·ã°ãã«ããµãã¹ã¯ã©ã€ãããŸãããã
[signal subscribeError:^(NSError *error) { // error from one of the signals } completed:^{ // side effects goes here. block get called when both signals completed }];
å°ãªããšã1ã€ã®ä¿¡å·ãæ©èœããªãå Žåã subscribeErrorãããã¯ãçºçããããšã«æ³šæããŠãã ããã æåã®ã·ã°ãã«ã倱æãããšã2çªç®ã®ã·ã°ãã«ã¯å®è¡ãããŸããã
3ïŒä¿¡å·ã«ã¯ãçµã¿èŸŒã¿ã®å»æ£ïŒãã£ã³ã»ã«ïŒã¡ã«ããºã ããããŸãã
ããšãã°ããŠãŒã¶ãŒã¯ããŒãäžã«ç»é¢ãé¢ããããšããããããŸãã ãã®å ŽåãããŠã³ããŒãæäœããã£ã³ã»ã«ããå¿ èŠããããŸãã ãã®ããžãã¯ãä¿¡å·ã«çŽæ¥å®è£ ã§ãããã®ããŒãæäœãžã®ãªã³ã¯ãä¿åããããšã¯ã§ããŸããã ããšãã°ã次ã®ããã«ãŠãŒã¶ãŒããŒã¿ãèªã¿èŸŒãä¿¡å·ãäœæã§ããŸãã
[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { __block NSURLSessionDataTask *task = [self GET:url parameters:parameters completion:^(id response, NSError *error) { if (!error) { [subscriber sendNext:response]; [subscriber sendCompleted]; } else { [subscriber sendError:error]; } }]; return [RACDisposable disposableWithBlock:^{ [task cancel]; }]; }]];
ç§ã¯æå³çã«ãã®ã³ãŒããåçŽåããŠã¢ã€ãã¢ã瀺ããŸããããå®éã«ã¯ããããã¯ã§èªå·±ããã£ããã£ããã¹ãã§ã¯ãããŸããã
ã·ã°ãã«ãåç §ããããšã«ããããã€ãã£ã³ã»ã«ããå¿ èŠãããããå€æã§ããŸãã
[[networkClient loadChats] takeUntil:self.rac_willDeallocSignal];
ãŸãã¯
[[networkClient loadChats] takeUntil:[self.cancelButton rac_signalForControlEvents:UIControlEventTouchUpInside]];
ãã®ã¢ãããŒãã®çŽ æŽãããç¹ã¯ãæäœãå®äºããå¿ èŠãããå Žåã«ã®ã¿äœ¿çšããæäœãžã®ãªã³ã¯ãä¿åããªãããšã§ãã ãããã£ãŠãäžéç¶æ ãç¶æããå¿ èŠããªããããã³ãŒãã¯ãã宣èšçã«èŠããŸãã
ãã¡ãããã·ã°ãã«ãæåã§ãã£ã³ã»ã«ããããšãã§ããŸã-RACDisposableãªããžã§ã¯ãïŒ subsribeNext / Error / Completedã¡ãœããããè¿ãããïŒãžã®åç §ãä¿åããå¿ èŠãªãšãã«-disposeã¡ãœãããçŽæ¥åŒã³åºããŸãã
ã·ã°ãã«ã䜿çšããŠãããã¯ãŒã¯ã¯ã©ã€ã¢ã³ããå®è£ ããããšã¯ãããªãåºç¯ãªè°è«ã®ãããã¯ã§ãã OctoKit -Reactive Cocoaã䜿çšããŠãããã¯ãŒã¯ã®åé¡ã解決ããæ¹æ³ã®å¥œäŸã§ãã Ash Furrowã¯ãiOSåãã®Functional Reactive Programmingã®æ¬ã§ããã®ãããã¯ãåãäžããŸããã
4.åäœäžã®ã·ã°ãã«
ããã€ãã®åé¡ã解決ããéã«ãã¢ããªã±ãŒã·ã§ã³ã®ããŸããŸãªéšåããã®ããŒã¿ãšã€ãã³ãã®éšåãçµã¿åãããŸããã ããŒã¿ã衚瀺ãããéåæã«å€æŽãããŸãã ãããã«ã€ããŠèããå Žåãããã¯å¿ é ã§ããã³ãŒãã«è¿œå ããæ¥ç¶ãšå€æ°ãäºæž¬ããããã«éèŠãªããšãšããŠãããããã¹ãŠãæéå ã«åæããæ¹æ³ãäºæž¬ããããšããŸãã
ããããã®äžé£ã®ã¢ã¯ã·ã§ã³ãå®æããããšãã³ãŒãã®èšè¿°ãéå§ããã¯ã©ã¹ã®ããŸããŸãªéšåããŸãã¯ããã€ãã®ã¯ã©ã¹ã§ããããžãã·ãŒãã£ã©ãã³ã®ããã«ãããžã§ã¯ãããããŸãã£ãŠãããç¡çšãªç¶æ ã®ã³ãŒãã®æ°ããè¡ã§æ±æãããŸãã
ãã®ãããªã³ãŒãã解æããã®ãã©ãã»ã©é£ãããç¥ã£ãŠããŸãïŒ ãããŠæã ãäœãèµ·ãã£ãŠããããç¥ãå¯äžã®æ¹æ³ã¯ãããã段éçã«ãããã°ããããšã§ãã
Reactive Cocoaã䜿çšããŠãã°ããããŠãããäžèšã®ãã¹ãŠã®åé¡ïŒãªã³ã¯ãåéæäœããããã¯ãŒã¯ã®æäœïŒã解決ããããã®åºç€ã¯ãããŒã¿ã¹ããªãŒã ïŒRACStreamïŒãšããŠã®ã¢ããªã±ãŒã·ã§ã³ã©ã€ããµã€ã¯ã«ã«ããããšãç解ããŸããã 次ã«ããŠãŒã¶ãŒãŸãã¯ãããã¯ãŒã¯ããã®ããŒã¿ãç¹å®ã®æ¹æ³ã§å€æããå¿ èŠããããŸãã ã¿ã¹ã¯ãã¯ããã«ç°¡åã«è§£æ±ºã§ããããšãããããŸããïŒ
2ã€ã®äŸãèŠãŠã¿ãŸãããã
ã¿ã¹ã¯ïŒ1
ããã¯ãæè¿å®äºããå®éã®ãããžã§ã¯ãã®äŸã§ãã
ã¡ãã»ãŒãžã亀æããæ©äŒããããã¿ã¹ã¯ã®1ã€ã¯ãã¢ããªã±ãŒã·ã§ã³ã¢ã€ã³ã³ã«æ£ããæ°ã®æªèªã¡ãã»ãŒãžã衚瀺ããããšã§ããã éåžžã®ã¿ã¹ã¯ã§ã¯ãããŸãããïŒ
æªèªã®ããŒã«å€ããããã£ãæ ŒçŽããChatViewModelã¯ã©ã¹ããããŸããã
@interface ChatViewModel : NSObject @property(nonatomic, readonly) BOOL unread // other public declarations @end
ãããŠãã³ãŒãã®ã©ããã«ããããã®ãã¥ãŒã¢ãã«ãå«ãdataSourcã®é åããããŸããã
äœããããã§ããïŒ æªèªããããã£ãå€æŽããããã³ã«ãæªèªã¡ãã»ãŒãžã®æ°ãæŽæ°ããŸãã èŠçŽ ã®æ°ã¯ããã¹ãŠã®ã¢ãã«ã®YESå€ã®æ°ãšçããããå¿ èŠããããŸãã ä¿¡å·ã䜿çšããŠãã®ãã¿ãŒã³ãå®è¡ããŠã¿ãŸãããã
RACSignal *unreadStatusChanged = [[RACObserve(self, dataSource) map:^id(NSArray *models) { RACSequence *sequence = [[models rac_sequence] map:^id(ChatViewModel *model) { return RACObserve(model, unread); }]; return [[RACSignal combineLatest:sequence] map:^id(RACTuple *unreadStatuses) { return [unreadStatuses.rac_sequence foldLeftWithStart:@0 reduce:^id(NSNumber *accumulator, NSNumber *unreadStatus) { return @(accumulator.integerValue + unreadStatus.integerValue); }]; }]; }] switchToLatest];
åå¿è ã«ã¯å°ãè€éã«èŠãããããããŸããããç解ããã®ã¯ãšãŠãç°¡åã§ãã
ãŸããé åã®å€åã芳å¯ããŸãã
RACObserve(self, dataSource)
æ°ãããã£ãããäœæããå€ããã£ãããåé€ã§ãããšæ³å®ãããŠãããããããã¯éèŠã§ãã RACã«ã¯å¯å€ã³ã¬ã¯ã·ã§ã³çšã®KVOããªããããDataSourceã¯ããªããžã§ã¯ããdataSourceã«è¿œå /åé€ããããã³ã«äžå€ã®é åã«ãªããŸãã RACObservã¯ãæ°ããå€ãdataSourceã«è¿œå ããããã³ã«æ°ããé åãè¿ãã·ã°ãã«ãè¿ããŸãã
ããŠãç§ãã¡ã¯ä¿¡å·ãåŸãŸãã...ããããããã¯ç§ãã¡ãæãã§ããä¿¡å·ã§ã¯ãªãã®ã§ããããå€æããå¿ èŠããããŸãã -mapæŒç®åã¯ããã®ã¿ã¹ã¯ã«æé©ã§ãã
[RACObserve(self, dataSource) map:^id(NSArray *models) { }]
ããããããã¯ã«ã¯å€ãã®ã¢ãã«ããããŸãã ãã¹ãŠã®ã¢ãã«ã®æªèªããããã£ã®åå€æŽã«ã€ããŠç¥ãããã®ã§ãä¿¡å·ããŸãã¯ä¿¡å·ã®é åããå¿ èŠã§ã-åã¢ãã«ã«1ã€ã®ä¿¡å·ïŒ
RACSequence *sequence = [[models rac_sequence] map:^id(ChatViewModel *model) { return RACObserve(model, unread); }];
ããã«ã¯æ°ãããã®ã¯äœããããŸããã RACSequenceãmapãRACObserve ã
æ³šïŒ ãã®å Žåãå€ã®ã·ãŒã±ã³ã¹ãä¿¡å·ã®ã·ãŒã±ã³ã¹ã«å€æããŸãã
å®éãããã»ã©å€ãã®ä¿¡å·ã¯å¿ èŠãããŸããã1ã€å¿ èŠã§ãããéèŠãªã®ã¯ã絶ããå€åããããŒã¿ãäžç·ã«åŠçããå¿ èŠãããããã§ãã RACã§ä¿¡å·ãçµåããã«ã¯ããã€ãã®æ¹æ³ããããããŒãºã«åã£ãæ¹æ³ãéžæã§ããŸãã
+ merge㯠ãã·ã°ãã«ããåäžã®ã¹ããªãŒã ã«å€ã転éããŸãã ããã¯ããŒãºãå®å šã«ã¯æºãããŠããŸããã次ã®ãããã¯ã§ã¯ãæåŸã®å€ïŒãã®å Žåã¯YESãŸãã¯NO ïŒã®ã¿ã衚瀺ãããŸãã
ïŒåèšãååŸããããã«ïŒãã¹ãŠã®å€ãç¥ãããã®ã§ã + composeLatestã䜿çšããŸããä¿¡å·ã®å€åãç£èŠããå€åãçºçãããšãã«ãã¹ãŠã®ä¿¡å·ã®æåŸã®å€ãéä¿¡ããŸãã 次ã®ãããã¯ã§ã¯ããã¹ãŠã®æªèªå€ã®ãã¹ãããã·ã§ããããèŠãããšãã§ããŸãã
[RACSignal combineLatest:sequence];
ããã§ãåäžã®å€ãå€æŽããããã³ã«ææ°ã®å€ã®é åãååŸã§ããŸãã ã»ãŒå®äºïŒ æ®ã£ãŠããå¯äžã®ã¿ã¹ã¯ã¯ããã®é åã§YESå€ãæ€åºãããåæ°ãèšç®ããããšã§ãã ç°¡åãªã«ãŒãã§ãããè¡ãããšãã§ããŸãããæåŸãŸã§æ©èœããreduceã¹ããŒãã¡ã³ãã䜿çšããŸãããã reduceã¯ãäºåå®çŸ©ãããã«ãŒã«ã«ãã£ãŠããŒã¿ã³ã¬ã¯ã·ã§ã³ãåäžã®ååéã«å€æããé¢æ°åããã°ã©ãã³ã°ã®æåãªé¢æ°ã§ãã RACã§ã¯ããã®é¢æ°ã¯-foldLeftWithStartïŒreduceïŒãŸãã¯-foldLeftWithStartïŒreduceïŒã§ãã
[unreadStatuses.rac_sequence foldLeftWithStart:@0 reduce:^id(NSNumber *accumulator, NSNumber *unreadStatus) { return @(accumulator.integerValue + unreadStatus.integerValue); }];
æåŸã«äžæãªç¹ã¯ããªãswitchToLatestãå¿ èŠãªã®ããšããããšã§ãã
ãããªãã§ã¯ãã·ã°ãã«ã®ã·ã°ãã«ãåãåããŸãïŒé åã®å€ãã·ã°ãã«ã«å€æããããïŒãunreadStatusChangedã«ãµãã¹ã¯ã©ã€ããããšãå€ã§ã¯ãªã次ã®ãããã¯ã§ã·ã°ãã«ãåãåããŸãã ãããä¿®æ£ããã«ã¯ã -flattenãŸãã¯-switchToLatest ïŒ å¹³åŠåãããŠããŸããããããã«éãããããŸãïŒã䜿çšã§ããŸãã
flattenã¯ãçŸåšãã©ããåãããŠãããµãã¹ã¯ã©ã€ããŒããå€æããè¿ãããä¿¡å·ã䜿çšããŠéä¿¡ãããå€ãåä¿¡ããããšãæå³ããŸãã -flattenã¯ã·ã°ãã«ããã·ã°ãã«ãåä¿¡ãããããã«éä¿¡ããã次ã®å€ãçµåããŸããã -switchToLatestã¯åãããšãè¡ããŸãããå€ã¯æåŸã®ã·ã°ãã«ããã®ã¿ãªãã€ã¬ã¯ãããŸãã
ç§ãã¡ã®å Žåã dataSourceã®å€ãããŒãžã§ã³ãžã®å€æŽãåãåããããªãã®ã§ãããã¯ããŸãæ©èœããŸãã ä¿¡å·ã¯æºåãã§ããŠããã䜿çšã§ããŸããå¯äœçšãå®è¡ããŸãããã
RAC([UIApplication sharedApplication], applicationIconBadgeNumber) = unreadStatusChanged;
åé¡ã®ã¹ããŒãã¡ã³ããã©ã®ããã«ã³ãŒãã«é¢é£ããŠãããã«æ°ã¥ããŸãããïŒ 1ã€ã®å Žæã§å®£èšçã«äœããããã®ããæžããŸããã äžéç¶æ ãç¶æããå¿ èŠã¯ãããŸããã
ã«ã¹ã¿ã ä¿¡å·ãäœæããããã®é©åãªæŒç®åãèŠã€ããããã«ããã¬ãŒã ã¯ãŒã¯ã®ããã¥ã¡ã³ããæãäžããå¿ èŠãããå ŽåããããŸãããããã ãã®äŸ¡å€ã¯ãããŸãã
ã¿ã¹ã¯ïŒ2
ãã¬ãŒã ã¯ãŒã¯ã®æ©èœã瀺ãå¥ã®ã¿ã¹ã¯ã次ã«ç€ºããŸãã ãã£ãããªã¹ãç»é¢ããããŸãããã¿ã¹ã¯ã¯ããã£ãããªã¹ãç»é¢ãéããç¶æ ã§ãæåŸã®ãã£ããã¡ãã»ãŒãžã衚瀺ããããšã§ããã çæãããä¿¡å·ã¯æ¬¡ã®ããã«ãªããŸãã
RACSignal *chatReceivedFirstMessage = [[RACObserve(self, dataSource) map:^id(NSArray *chats) { RACSequence *sequence = [[[chats rac_sequence] filter:^BOOL(ChatViewModel *chat) { return ![chat hasMessages]; }] map:^id(ChatViewModel *chat) { return [[RACObserve(chat, lastMessage) ignore:nil] take:1]; }] ; return [RACSignal merge:sequence]; }] switchToLatest];
ãããäœã§æ§æãããããèŠãŠã¿ãŸãããã
ãã®äŸã¯ãåã®äŸãšéåžžã«ãã䌌ãŠããŸãã é åã芳å¯ãããããæŒç®åãå€ãä¿¡å·ã«å€æããææ°ã®ä¿¡å·ã®ã¿ãèæ ®ããŸãã
ãŸããã¡ãã»ãŒãžã®ãããã£ããã«ã¯é¢å¿ããªããããå€æãããã¯ã§dataSourceããã£ã«ã¿ãŒåŠçããŸãã
次ã«ãåã³RACObserveã䜿çšããŠãå€ãã·ã°ãã«ã«å€æããŸãã
return [[RACObserve(chat, lastMessage) ignore:nil] take:1];
RACObserveã«ãã£ãŠçæãããã·ã°ãã«ã¯ããããã£ã®åæå€ïŒnilïŒã§èµ·åããããã -ignore ïŒãç¡èŠããå¿ èŠããããŸãã æŒç®åãå¿ èŠã§ãã
ã¿ã¹ã¯ã®2çªç®ã®éšåã¯ãæåã®çä¿¡ã¡ãã»ãŒãž-TakeïŒã®ã¿ãèæ ®ããããšã§ãã ããã®äžè©±ãããŸãã ã·ã°ãã«ã¯ãæåã®å€ãåä¿¡ãããšããã«å®äºïŒããã³åé€ïŒãããŸãã
æ確ã«ããããã ãã§ãã ãã®ã³ãŒãã§äœæãã3ã€ã®æ°ããä¿¡å·ããããŸãã æåã¯RACObserveãã¯ãã«ãã£ãŠäœæããã2çªç®ã¯æåã«æ°ããäœæãããã·ã°ãã«ã®ã¹ããŒãã¡ã³ãã®-ignoreïŒãåŒã³åºããŠã3çªç®ã¯-takeïŒãåŒã³åºããŠ-ignoreã«ãã£ãŠäœæãããã·ã°ãã«ã«ãã£ãŠïŒ
åã®äŸã®ããã«ãçæãããä¿¡å·ã«åºã¥ããŠ1ã€ã®ä¿¡å·ãå¿ èŠã§ãã åã®äŸã®ããã«å€ãæ°ã«ããªãããã -mergeïŒã䜿çšããŠæ°ããããŒãžãããã¹ããªãŒã ãäœæããŸãã
å¯äœçšæéïŒ
[chatReceivedFirstMessage subscribeNext:^(id x) { // switching to chat screen }];
æ³šïŒ ä¿¡å·ã«å«ãŸããå€ã¯äœ¿çšããŸããã ãã ãã xã«ã¯åä¿¡ããã¡ãã»ãŒãžãå«ãŸããŸãã
ããã§ã¯ãReactive Cocoaã®å°è±¡ã«ã€ããŠå°ã話ããŸãããã
Reactive Cocoaã«ã€ããŠç§ãæ¬åœã«å¥œããªããš
1.ãããžã§ã¯ãã§ã®äœ¿çšã¯ç°¡åã§ãã ãã¬ãŒã ã¯ãŒã¯ã¯çã£ãããã«ææžåãããŠããŸãã GitHubã«ã¯å€ãã®äŸããããåã¯ã©ã¹ãšã¡ãœããã®è©³çŽ°ãªèª¬æãå€æ°ã®èšäºããããªããã¬ãŒã³ããŒã·ã§ã³ããããŸãã
2.ããã°ã©ãã³ã°ã¹ã¿ã€ã«ãå®å šã«å€æŽããå¿ èŠã¯ãããŸããã ãŸããUIãã€ã³ãã£ã³ã°ããããã¯ãŒã¯ã©ãããŒãGitHubã䜿çšãããã®ä»ã®ãœãªã¥ãŒã·ã§ã³ãªã©ãåé¡ã«å¯Ÿããæ¢åã®ãœãªã¥ãŒã·ã§ã³ã䜿çšã§ããŸãã ãã®åŸã段éçã«ãReactive Cocoaã®ãã¹ãŠã®æ©èœãç解ã§ããŸãã
3.åé¡ã®è§£æ±ºæ¹æ³ãåœä»€åãã宣èšåã«å€ãããŸãã ããã°ã©ãã³ã°ã®æ©èœçãªã¹ã¿ã€ã«ãiOSã³ãã¥ããã£ã§ãŸããŸãäžè¬çã«ãªã£ãŠããŠãããããå€ãã®äººãåºæ¬çã«èãæ¹ãå€ããããšã¯å°é£ã§ãã Reactive Cocoaã«ã¯ãã æ¹æ³ ãã¹ã¿ã€ã«ã§ã¯ãªããäœããããã¹ã¿ã€ã«ã§éä¿¡ããã®ã«åœ¹ç«ã€å€ãã®ããŒã«ããããããå€æŽãå ããã®ã«åœ¹ç«ã¡ãŸãã
Reactive Cocoaãæ°ã«å ¥ããªãç¹
1. RACïŒïŒãŸãã¯RACObserveïŒïŒãã¯ãã®æ®åã
2. RACSignalsã䜿çšãããšæ·±ãã¹ã¿ãã¯ãã¬ãŒã¹ãçºçãããããã³ãŒãã®ãããã°ãå°é£ãªå ŽåããããŸãã
3. ã¿ã€ãã»ãŒãã§ã¯ãããŸããïŒ subscribeNextãããã¯ã§ã©ã®ã¿ã€ããæåŸ ããããããããŸããïŒã ãã®å Žåã®æè¯ã®è§£æ±ºçã¯ãäŸãšããŠããããªãã¯ã€ã³ã¿ãŒãã§ã€ã¹ã§ä¿¡å·ãææžåããããšã§ãã
/** * Returns a signal which will send a User and complete or error. */ -(RACSignal *)loginUser;
ç§ãå©ããããšã¯ã§ããŸããããã¹ãŠã£ããã«èšåããŸã
Reactive Cocoaã¯Objective-Cã§ãç¹ã«Objective-Cåãã«äœæãããŠããŸãã ãããããã¡ãããSwiftã®äººæ°ãé«ãŸã£ãŠããä»ããã¬ãŒã ã¯ãŒã¯éçºè ã¯æ ããŠããããã§ã¯ãããŸããã 圌ãã¯ãReactive CocoaïŒGreat Swiftening closeïŒã§äœ¿çšããããã«ãå®éã«Swift APIãäœæããŸãã æ§ããã«èšãã°ããã©ãã¯ãžã£ãã¯ãšå£²æ¥å©Šããžã§ããªãã¯ãããã³ãªãã¬ãŒã¿ãŒã®ãªãŒããŒããŒããåããæ°ããããŒãžã§ã³3.0ããããŸãã
ãã®åŸãRACã¯ããã«å€ãã®ãã¡ã³ãç²åŸãããšç¢ºä¿¡ããŠããŸãã ãŸããªãããã¯ããšéåå®å šæ§ãåªãå®ç§äž»çŸ©è ã¯ãReactive Cocoaã䜿çšããã«èªåèªèº«ãä¿è·ãããšããè°è«ãæã¡ãŸããã
ãããã«
æ©èœçã§å¿çæ§ã®é«ãã¢ãããŒãã«ãããæ¥åžžã®ã¿ã¹ã¯ãç°¡çŽ åã§ããŸãã ããããã第äžã«ãRACã®æŠå¿µã¯è€éãããããã«æããããã®æ±ºå®ã¯é¢åã§å·šå€§ã§ããããªãã¬ãŒã¿ãŒã®æ°ã¯ããªãã倧ããæ··ä¹±ãããŸãã ããããåŸã§ãããããã¹ãŠãåçŽãªã¢ã€ãã¢ãæã£ãŠããããšãæããã«ãªããŸãã
ããŒã¿ïŒå ¥åãŸãã¯åºåïŒãã¹ããªãŒã ãšããŠæ瀺ããŸããã€ãã³ãïŒããŒã¿ããšã©ãŒãå®äºïŒã®ãã€ãã®ãããªã¹ããªãŒã ãã·ã°ãã«ãšã·ãŒã±ã³ã¹ã¯ã¹ããªãŒã ã§ããã·ã°ãã«ã¯å¶åŸ¡ãããã¹ããªãŒã ã§ããäœãããããšããŠãŒã¶ãŒã«å ¥åãäžãããããã£ã¹ã¯ããã®éåæããŒããªã©ãè¡ããŸããã·ãŒã±ã³ã¹ã¯ãæ ŒçŽåŒãã©ã€ããåããã¹ã¬ããã§ããäœããå¿ èŠãªå Žåã¯ãã·ãŒã±ã³ã¹ïŒã³ã¬ã¯ã·ã§ã³ãªã©ïŒããæç»ããŸããä»ã®ãã¹ãŠã®å€ææŒç®åããã³çµåæŒç®åã¯ãããããã¹ãŠãäžç·ã«å€æããŸãïŒå€æããã£ã«ã¿ãŒãçµåãswitchToLatestããã§ãŒã¯ãªã©ïŒã
ããã«ããã¹ãŠã®ã€ãã³ãã¯ãäœæãããã¹ããªãŒã å ã®ãµãã¹ã¯ã©ã€ããŒã«é ä¿¡ãããããšãèŠããŠããå¿ èŠããããŸãããããæå®ããå¿ èŠãããå Žåã¯ã-deliverOnæŒç®åã䜿çšããŠãã®RACSchedulerïŒGCDãã¥ãŒã«äŒŒãŠããŸããããã£ã³ã»ã«ããæ©èœãæã€ã¯ã©ã¹ïŒãé©çšããŸãïŒ
äžè¬çãªã«ãŒã«ãšããŠãããªãã¯æ瀺çã€ã³ã¿ãŒãã§ã€ã¹ãæŽæ°ããã ãã§ã[RACScheduler mainThreadScheduler]ãæå®ããå¿ èŠããããŸãããç¬èªã®å®è£ ãæžãããšãã§ãRACScedulerãã®ãããªãã®ãç¹å®ããŠãããªãããŠããååŒãCoreDataãã