in in der 
響應式編程 
張景隆 
! 
iOS Dev Club 
蘋果貓咖啡 
MOPCON 
2014
ReactiveCocoa
Questions 
•聽過 RAC 
•很熟悉 RAC 
•已經⽤用在專案上
What is ReactiveCocoa 
ReactiveCocoa is an open source library that brings 
Functional Reactive Programming paradigm to 
Objective-C. It was created by Josh Abernathy & 
Justin Spahr-Summers in the development of GitHub 
for Mac.
What is Stream?
⼤大家覺得⽤用起來像是
但實際⽤用起來
看了 ReactiveCocoa 的 
! 
README
Agenda 
• 介紹 FRP 
• 事件與⾮非同步等問題 
• 介紹 ReactiveCocoa 
• RAC 基礎 
• RAC Example 
• iOS Dev Club 社群介紹
Appletone 
• Perl 
• Linux 
• Java 
• Ruby 
• Objective-C 
• Swift
biichat BTWCar CWMoney
The Information Processing Cycle
Imperative Programming 
int 
x, 
y, 
z; 
x 
= 
1; 
y 
= 
1; 
z 
= 
x 
+ 
y; 
// 
1+1 
y 
= 
2; 
printf("%d", 
z); 
// 
z=2
Reactive Programming 
int 
x, 
y, 
z; 
x 
= 
1; 
y 
= 
1; 
z 
= 
x 
+ 
y; 
// 
1+1 
y 
= 
2; 
printf("%d", 
z); 
// 
z=3
Functional Programming 
Swift: 
map(1...3){ $0 * 5 } 
ObjC: 
NSMutableArray *arr = [NSMutableArray new]; 
for(int i=1; i<=3; i++) { 
[arr addObject:@(i * 5)]; 
}
Functional Reactive Programming 
即 FP + RP 綜合兩種特性 
! 
賦予 RP 擁有許多 FP 的運算函⽰示
Problems 
• Target-Action 
• Delegate 
• Block 
• Notifications 
• KVO 
! 
• ⽅方式太多 
• 缺乏⼀一致性 
• 商業邏輯分散 
• 難以整合各個事件
RAC dealing with 
One of the major advantages of RAC is 
that it provides a single, unified approach 
to dealing with 
! 
1. asynchronous behaviors, 
2. including delegate methods, 
3. callback blocks, 
4. target-action mechanisms, 
5. notifications, 
6. and KVO.
Why ReactiveCocoa?
Mattt Thompson : 
“ The brave new era for Objective-C “ 
Justin DeWind : 
“ The Future of Cocoa Programming “ 
http://nshipster.com/reactivecocoa/ 
http://spin.atomicobject.com/2013/04/28/reactivecocoa/
Terms 
• RACSignal vs. RACSequence 
• Cold or Hot Signals
RACSignal vs. RACSequence 
pull-­‐driven push-­‐driven
Terms 
• RACSignal vs. RACSequence 
• Cold or Hot Signals
Cold or Hot Signals 
• Hot Signals 
• 按鈕事件 
• 事件即時通知 
! 
• Cold Signals 
• 網路事件 
• 不會⾺馬上有結果
Macros 
• RACObserve() 
• 建⽴立 RACSignal 
• 數值變動發動 
! 
! 
• RAC() 
• 放在 assignment operator 的左邊 
• 綁定 RACSignal 給的數值
RACObserve 
new value 
! 
! 
[RACObserve(self, 
username) 
subscribeNext:^(NSString 
*newName) 
{ 
self.consoleLabel.text 
= 
newName; 
}]; 
RACSignal Subscriber
RAC 
RACSignal 
binding 
Value 
RAC(self.consoleLabel, text) = RACObserve(self, username);
廣泛的使⽤用 KVO 
為什麼不⽤用 KVO 就好?
信號可被串接 
KVO 不好⽤用 
蘋果的⽂文件寫的很讚 
但是API設計的很爛
Example I 
! • rac_textSignal 
• map 
• avoiding retain cycles
Example I 
[self.textField.rac_textSignal subscribeNext:^(id x) { 
self.console.text = x; 
}]; 
OR 
RAC(self.console, text) = self.textField.rac_textSignal;
Example I 
#import <RACEXTScope.h> 
@weakify(self); 
[[self.textField.rac_textSignal 
map:^id(id value) { 
return [value uppercaseString]; 
}] 
subscribeNext:^(id x) { 
@strongify(self); 
self.console.text = x; 
}];
Example II 
Login Demo
Example II 
RACSignal *nameSignal = self.nameTextField.rac_textSignal; 
RACSignal *passSignal = self.passTextField.rac_textSignal; 
RAC(self.loginButton, enabled) = 
[RACSignal combineLatest:@[nameSignal, passSignal] 
reduce:^id(NSString *name, NSString *pass){ 
return @( ![name isEqualToString:@""] && 
![pass isEqualToString:@""] ); 
}];
Example III 
NSUserDefault
Example III 
! 
RACSignal *tokenSignal = [[NSUserDefaults 
standardUserDefaults] 
rac_channelTerminalForKey:@"token"]; 
[[tokenSignal filter:^BOOL(NSString *token) { 
return [token chuzzle]?YES:NO; 
}] 
subscribeNext:^(NSString *token) { 
[self loadData]; 
}];
Example IV 
! 
AFNetworkReachabilityManager 
AFNetworking
AFNetworkReachabilityManager *reachabilityManager = 
[AFNetworkReachabilityManager sharedManager]; 
RACSignal *isReachable = 
[RACObserve( 
reachabilityManager, networkReachabilityStatus) 
map:^(NSNumber *networkReachabilityStatus) { 
switch (networkReachabilityStatus.intValue) { 
case AFNetworkReachabilityStatusReachableViaWWAN: 
case AFNetworkReachabilityStatusReachableViaWiFi: 
return @YES; 
} 
return @NO; 
}];
[[AFHTTPRequestOperationManager alloc] init]; 
! 
NSString *URLString = @"http://ip.jsontest.com"; 
AFHTTPRequestOperationManager *manager = 
RACSignal *myIPSignal = [RACSignal createSignal:^RACDisposable 
*(id<RACSubscriber> subscriber) { 
[manager GET:URLString parameters:nil 
success:^(AFHTTPRequestOperation *op, id response) { 
! 
} failure:^(AFHTTPRequestOperation *op, NSError *e) { 
! 
} 
]; 
return nil; 
}]; 
[subscriber sendNext:response]; 
[subscriber sendCompleted]; 
[subscriber sendError:e]; 
[myIPSignal subscribeNext:^(id response) { 
// 
NSLog(@"My IP => %@", response[@"ip"]); 
}];
Example V 
• 檢查 網路狀態 以及 雲端伺服器 是否正常 
• 使⽤用者是否啟⽤用同步功能 
• 有待同步資料 
• 需綁定 FB Account 
• 可設定 WIFI 或 3G 底下同步
RACSignal *networkSignal = RACObserve(self, isNetworkReachable); 
RACSignal *cloudSignal = RACObserve(self, isUsedCloud); 
RACSignal *facebookSignal = RACObserve(self, isFacebookBinding); 
RACSignal *wifiOnlySignal = RACObserve(self, isWifiSyncOnly); 
! 
NSArray *signals = @[networkSignal, cloudSignal, facebookSignal, 
wifiOnlySignal]; 
RACSignal *preparedSignal = [RACSignal combineLatest:signals 
reduce:^id (id network, id cloud, id facebook, id wifi){ 
return @([network boolValue] && [cloud boolValue] && [facebook 
boolValue] && [wifi boolValue]); 
}]; 
RACSignal *queueSignal = RACObserve(self, uploadQueue); 
[[[RACSignal combineLatest:@[preparedSignal, queueSignal]] 
filter:^BOOL(RACTuple *tuple) { 
return [[tuple first] boolValue]; 
}] 
subscribeNext:^(RACTuple *tuple) { 
// 
id task = [tuple second]; 
// do something ... 
}];
RACSignal *queueSignal = RACObserve(self, uploadQueue); 
[[[RACSignal combineLatest:@[preparedSignal, queueSignal]] 
filter:^BOOL(RACTuple *tuple) { 
return [[tuple first] boolValue]; 
}] 
subscribeNext:^(RACTuple *tuple) { 
deliverOn:[RACScheduler scheduler]] 
// 
id task = [tuple second]; 
// do something ... 
}]; 
[ 
Asynchronous Operation
RACSignal+Operations.h
Recap 
• RACSequence & RACSignal 的差別 
• 熱信號 與 冷信號 
• 實⽤用的 Macros: RACObserve() & RAC() 
• 信號 的 建⽴立、訂閱、合併、轉換、過濾 
• 如何建⽴立⾮非同步的網路信號
iOS Dev Club
! iOS Dev Club 開發者聚會 
iOS Dev Club 成⽴立於 2011 年 5 ⽉月。 
我們是以 Facebook 的社團(groups)成⽴立,主要是為了在中部附近的 iOS App 設計 
開發同好,可以經常性碰⾯面互相學習的聚會,我們的地點都選擇在咖啡館,固 
定在每個⽉月最後⼀一週的星期六上午,每次都會安排主題分享研習。 
! 
第⼀一年,我們在彰化的顏⽒氏牧場II舉辦。 
第⼆二年,我們在台中的默契咖啡舉辦。 
第三年,我們挑戰環島~ 
! 
因為每個⽉月中旬發出聚會訊息時,最常⾒見的歎息就是:為什麼不是在XXX? 
(XXX=請⾃自⾏行帶⼊入離⾃自⼰己居住熟悉或最近的城市) 
於是第三年,我們分別在台北、新⽵竹、台中、⾼高雄辦了六場的 iOS Dev Club 開環 
島開發這聚會,我們到這幾個城市拜訪當地的 iOS 開發社團、專業的程式設計社 
團,互相交流也互相認識。 
! 
第四年,我們來到了台中市⻯⿓龍井區的蘋果貓咖啡舉辦,我們除了在這裡每個⽉月 
舉辦⼀一次之外,也會陸續在每週都有研習課程加⼊入,請⼤大家密切注意我們在 
Facebook 粉絲專⾴頁發佈的活動資訊。 
http://iosdev.club/
iOS Dev Club 環島開發聚#1 臺北 
2013/5/26
iOS Dev Club 環島開發聚#2 新⽵竹 
2013/6/29
iOS Dev Club 環島開發聚#3 ⾼高雄 
2013/07/27
iOS Dev Club 環島開發聚#6 臺北 
2013/11/30
WWDC 2014 研習分享 
2014/06/28
Apple 9/9 發表會後的設計須知 
開發者的頭豈⽌止於⼤大 
2014/09/27
Apple 9/9 發表會後的設計須知 
開發者的頭豈⽌止於⼤大 
2014/09/27
iOS Dev Club 資源
http://iosdev.club
https://www.facebook.com/ios.dev.club
https://www.youtube.com/user/iOSDevClub
https://github.com/iOSDevClub
有問題 請上 
iOS Dev Club 
https://www.facebook.com/ios.dev.club
http://taichung.iiiedu.org.tw/swift.html
Thanks for coming ! 
@evillon 
appletone.tw@gmail.com
in in der 響應式編程

in in der 響應式編程

  • 1.
    in in der 響應式編程 張景隆 ! iOS Dev Club 蘋果貓咖啡 MOPCON 2014
  • 2.
  • 3.
    Questions •聽過 RAC •很熟悉 RAC •已經⽤用在專案上
  • 4.
    What is ReactiveCocoa ReactiveCocoa is an open source library that brings Functional Reactive Programming paradigm to Objective-C. It was created by Josh Abernathy & Justin Spahr-Summers in the development of GitHub for Mac.
  • 5.
  • 7.
  • 9.
  • 11.
  • 13.
    Agenda • 介紹FRP • 事件與⾮非同步等問題 • 介紹 ReactiveCocoa • RAC 基礎 • RAC Example • iOS Dev Club 社群介紹
  • 14.
    Appletone • Perl • Linux • Java • Ruby • Objective-C • Swift
  • 15.
  • 16.
  • 17.
    Imperative Programming int x, y, z; x = 1; y = 1; z = x + y; // 1+1 y = 2; printf("%d", z); // z=2
  • 18.
    Reactive Programming int x, y, z; x = 1; y = 1; z = x + y; // 1+1 y = 2; printf("%d", z); // z=3
  • 19.
    Functional Programming Swift: map(1...3){ $0 * 5 } ObjC: NSMutableArray *arr = [NSMutableArray new]; for(int i=1; i<=3; i++) { [arr addObject:@(i * 5)]; }
  • 20.
    Functional Reactive Programming 即 FP + RP 綜合兩種特性 ! 賦予 RP 擁有許多 FP 的運算函⽰示
  • 21.
    Problems • Target-Action • Delegate • Block • Notifications • KVO ! • ⽅方式太多 • 缺乏⼀一致性 • 商業邏輯分散 • 難以整合各個事件
  • 22.
    RAC dealing with One of the major advantages of RAC is that it provides a single, unified approach to dealing with ! 1. asynchronous behaviors, 2. including delegate methods, 3. callback blocks, 4. target-action mechanisms, 5. notifications, 6. and KVO.
  • 23.
  • 24.
    Mattt Thompson : “ The brave new era for Objective-C “ Justin DeWind : “ The Future of Cocoa Programming “ http://nshipster.com/reactivecocoa/ http://spin.atomicobject.com/2013/04/28/reactivecocoa/
  • 25.
    Terms • RACSignalvs. RACSequence • Cold or Hot Signals
  • 26.
    RACSignal vs. RACSequence pull-­‐driven push-­‐driven
  • 28.
    Terms • RACSignalvs. RACSequence • Cold or Hot Signals
  • 29.
    Cold or HotSignals • Hot Signals • 按鈕事件 • 事件即時通知 ! • Cold Signals • 網路事件 • 不會⾺馬上有結果
  • 30.
    Macros • RACObserve() • 建⽴立 RACSignal • 數值變動發動 ! ! • RAC() • 放在 assignment operator 的左邊 • 綁定 RACSignal 給的數值
  • 31.
    RACObserve new value ! ! [RACObserve(self, username) subscribeNext:^(NSString *newName) { self.consoleLabel.text = newName; }]; RACSignal Subscriber
  • 32.
    RAC RACSignal binding Value RAC(self.consoleLabel, text) = RACObserve(self, username);
  • 33.
  • 34.
    信號可被串接 KVO 不好⽤用 蘋果的⽂文件寫的很讚 但是API設計的很爛
  • 35.
    Example I !• rac_textSignal • map • avoiding retain cycles
  • 36.
    Example I [self.textField.rac_textSignalsubscribeNext:^(id x) { self.console.text = x; }]; OR RAC(self.console, text) = self.textField.rac_textSignal;
  • 37.
    Example I #import<RACEXTScope.h> @weakify(self); [[self.textField.rac_textSignal map:^id(id value) { return [value uppercaseString]; }] subscribeNext:^(id x) { @strongify(self); self.console.text = x; }];
  • 38.
  • 40.
    Example II RACSignal*nameSignal = self.nameTextField.rac_textSignal; RACSignal *passSignal = self.passTextField.rac_textSignal; RAC(self.loginButton, enabled) = [RACSignal combineLatest:@[nameSignal, passSignal] reduce:^id(NSString *name, NSString *pass){ return @( ![name isEqualToString:@""] && ![pass isEqualToString:@""] ); }];
  • 41.
  • 42.
    Example III ! RACSignal *tokenSignal = [[NSUserDefaults standardUserDefaults] rac_channelTerminalForKey:@"token"]; [[tokenSignal filter:^BOOL(NSString *token) { return [token chuzzle]?YES:NO; }] subscribeNext:^(NSString *token) { [self loadData]; }];
  • 43.
    Example IV ! AFNetworkReachabilityManager AFNetworking
  • 44.
    AFNetworkReachabilityManager *reachabilityManager = [AFNetworkReachabilityManager sharedManager]; RACSignal *isReachable = [RACObserve( reachabilityManager, networkReachabilityStatus) map:^(NSNumber *networkReachabilityStatus) { switch (networkReachabilityStatus.intValue) { case AFNetworkReachabilityStatusReachableViaWWAN: case AFNetworkReachabilityStatusReachableViaWiFi: return @YES; } return @NO; }];
  • 45.
    [[AFHTTPRequestOperationManager alloc] init]; ! NSString *URLString = @"http://ip.jsontest.com"; AFHTTPRequestOperationManager *manager = RACSignal *myIPSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [manager GET:URLString parameters:nil success:^(AFHTTPRequestOperation *op, id response) { ! } failure:^(AFHTTPRequestOperation *op, NSError *e) { ! } ]; return nil; }]; [subscriber sendNext:response]; [subscriber sendCompleted]; [subscriber sendError:e]; [myIPSignal subscribeNext:^(id response) { // NSLog(@"My IP => %@", response[@"ip"]); }];
  • 46.
    Example V •檢查 網路狀態 以及 雲端伺服器 是否正常 • 使⽤用者是否啟⽤用同步功能 • 有待同步資料 • 需綁定 FB Account • 可設定 WIFI 或 3G 底下同步
  • 48.
    RACSignal *networkSignal =RACObserve(self, isNetworkReachable); RACSignal *cloudSignal = RACObserve(self, isUsedCloud); RACSignal *facebookSignal = RACObserve(self, isFacebookBinding); RACSignal *wifiOnlySignal = RACObserve(self, isWifiSyncOnly); ! NSArray *signals = @[networkSignal, cloudSignal, facebookSignal, wifiOnlySignal]; RACSignal *preparedSignal = [RACSignal combineLatest:signals reduce:^id (id network, id cloud, id facebook, id wifi){ return @([network boolValue] && [cloud boolValue] && [facebook boolValue] && [wifi boolValue]); }]; RACSignal *queueSignal = RACObserve(self, uploadQueue); [[[RACSignal combineLatest:@[preparedSignal, queueSignal]] filter:^BOOL(RACTuple *tuple) { return [[tuple first] boolValue]; }] subscribeNext:^(RACTuple *tuple) { // id task = [tuple second]; // do something ... }];
  • 49.
    RACSignal *queueSignal =RACObserve(self, uploadQueue); [[[RACSignal combineLatest:@[preparedSignal, queueSignal]] filter:^BOOL(RACTuple *tuple) { return [[tuple first] boolValue]; }] subscribeNext:^(RACTuple *tuple) { deliverOn:[RACScheduler scheduler]] // id task = [tuple second]; // do something ... }]; [ Asynchronous Operation
  • 50.
  • 51.
    Recap • RACSequence& RACSignal 的差別 • 熱信號 與 冷信號 • 實⽤用的 Macros: RACObserve() & RAC() • 信號 的 建⽴立、訂閱、合併、轉換、過濾 • 如何建⽴立⾮非同步的網路信號
  • 52.
  • 53.
    ! iOS DevClub 開發者聚會 iOS Dev Club 成⽴立於 2011 年 5 ⽉月。 我們是以 Facebook 的社團(groups)成⽴立,主要是為了在中部附近的 iOS App 設計 開發同好,可以經常性碰⾯面互相學習的聚會,我們的地點都選擇在咖啡館,固 定在每個⽉月最後⼀一週的星期六上午,每次都會安排主題分享研習。 ! 第⼀一年,我們在彰化的顏⽒氏牧場II舉辦。 第⼆二年,我們在台中的默契咖啡舉辦。 第三年,我們挑戰環島~ ! 因為每個⽉月中旬發出聚會訊息時,最常⾒見的歎息就是:為什麼不是在XXX? (XXX=請⾃自⾏行帶⼊入離⾃自⼰己居住熟悉或最近的城市) 於是第三年,我們分別在台北、新⽵竹、台中、⾼高雄辦了六場的 iOS Dev Club 開環 島開發這聚會,我們到這幾個城市拜訪當地的 iOS 開發社團、專業的程式設計社 團,互相交流也互相認識。 ! 第四年,我們來到了台中市⻯⿓龍井區的蘋果貓咖啡舉辦,我們除了在這裡每個⽉月 舉辦⼀一次之外,也會陸續在每週都有研習課程加⼊入,請⼤大家密切注意我們在 Facebook 粉絲專⾴頁發佈的活動資訊。 http://iosdev.club/
  • 54.
    iOS Dev Club環島開發聚#1 臺北 2013/5/26
  • 55.
    iOS Dev Club環島開發聚#2 新⽵竹 2013/6/29
  • 56.
    iOS Dev Club環島開發聚#3 ⾼高雄 2013/07/27
  • 57.
    iOS Dev Club環島開發聚#6 臺北 2013/11/30
  • 58.
  • 59.
    Apple 9/9 發表會後的設計須知 開發者的頭豈⽌止於⼤大 2014/09/27
  • 60.
    Apple 9/9 發表會後的設計須知 開發者的頭豈⽌止於⼤大 2014/09/27
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
    有問題 請上 iOSDev Club https://www.facebook.com/ios.dev.club
  • 67.
  • 68.
    Thanks for coming! @evillon appletone.tw@gmail.com