ReactiveCocoa(其簡稱爲RAC)是由Github 開源的一個應用於iOS和OS X開發的新框架。RAC具備函數式編程(FP)和響應式編程(RP)的特性。它主要吸收了.Net的 Reactive Extensions的設計和實現。編程
ReactiveCocoa 的宗旨是Streams of values over time ,隨着時間變化而不斷流動的數據流。數組
ReactiveCocoa 主要解決了如下這些問題:markdown
UI數據綁定框架
用戶交互事件綁定async
解決狀態以及狀態之間依賴過多的問題ide
消息傳遞機制的大統一函數式編程
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
複製代碼
- (void) keyboardWillShow:(NSNotification *)note {
NSLog(@"鍵盤彈出了");
}
複製代碼
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
}
複製代碼
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
NSLog(@"%@",x);
}];
複製代碼
NSConcreteNotification 0x6000000c5170 {name = UIKeyboardWillShowNotification; userInfo = {
UIKeyboardAnimationCurveUserInfoKey = 7;
UIKeyboardAnimationDurationUserInfoKey = "0.25";
UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {390, 336}}";
UIKeyboardCenterBeginUserInfoKey = "NSPoint: {195, 1012}";
UIKeyboardCenterEndUserInfoKey = "NSPoint: {195, 676}";
UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 844}, {390, 336}}";
UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 508}, {390, 336}}";
UIKeyboardIsLocalUserInfoKey = 1;
}}
複製代碼
普通寫法函數
@interface TestModel : NSObject
@property (assign, nonatomic) int age;
@property (assign, nonatomic) int height;
@end
複製代碼
#import "KVOViewController.h"
#import "TestModel.h"
@interface KVOViewController ()
@property (strong, nonatomic) TestModel *testModel1;
@end
@implementation KVOViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.testModel1 = [[TestModel alloc] init];
self.testModel1.age = 1;
self.testModel1.height = 11;
// 給testModel1對象添加KVO監聽 當KVO監聽age屬性變化
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.testModel1 addObserver:self forKeyPath:@"age" options:options context:@"123"];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.testModel1.age = 20;
self.testModel1.height = 30;
}
// 當監聽對象的屬性值發生改變時,就會調用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"監聽到%@的%@屬性值改變了 - %@ - %@", object, keyPath, change, context);
}
- (void)dealloc {
[self.testModel1 removeObserver:self forKeyPath:@"age"];
[self.testModel1 removeObserver:self forKeyPath:@"height"];
}
複製代碼
#define RACObserve(TARGET, KEYPATH) _RACObserve(TARGET, KEYPATH)oop
[RACObserve(self.testModel1, age)subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
複製代碼
1. 遵照代理 <UITextFieldDelegate>
2. 空間 @property (weak, nonatomic) IBOutlet UITextField *textField;
3. 代理的響應者 self.textField.delegate = self;
4.代理方法
- (void)textFieldDidBeginEditing:(UITextField *)textField {
NSLog(@"開始編輯");
}
複製代碼
self.textField.delegate = self;
[[self rac_signalForSelector:@selector(textFieldDidBeginEditing:) fromProtocol:@protocol(UITextFieldDelegate)] subscribeNext:^(RACTuple * _Nullable x) {
NSLog(@"%@",x);
}];
<RACTuple: 0x600000dd9130> (
"<UITextField: 0x127d0bf90; frame = (97 118; 220 34); text = ''; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x6000001e6f70>; borderStyle = RoundedRect; background = <_UITextFieldSystemBackgroundProvider: 0x600000f8eb80: backgroundView=<_UITextFieldRoundedRectBackgroundViewNeue: 0x127d0e710; frame = (0 0; 220 34); opaque = NO; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x600000f8ec60>>, fillColor=<UIDynamicModifiedColor: 0x6000001874e0; contrast = normal, baseColor = <UIDynamicSystemColor: 0x600001a9bb40; name = systemRedColor>>, textfield=<UITextField 0x127d0bf90>>; layer = <CALayer: 0x600000fe3ee0>>"
)
複製代碼
[self.button addTarget:self action:@selector(Click:) forControlEvents:UIControlEventTouchUpInside];
- (void)Click:(UIButton *)sender {
NSLog(@"按鈕被點擊");
}
複製代碼
[[self.button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"%@",x);
}];
<UIButton: 0x15a50d9f0; frame = (101 240; 213 205); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x60000262fb60>>
複製代碼
[self.textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
複製代碼
當在self.textField輸入文字h時,會實時打印出變化後的文字
2019-05-16 18:02:58.562309+0800 001---RAC[54530:4536864] h
2019-05-16 18:02:59.049225+0800 001---RAC[54530:4536864] hh
2019-05-16 18:02:59.288995+0800 001---RAC[54530:4536864] hhh
複製代碼
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
self.label.userInteractionEnabled = YES;
[self.label addGestureRecognizer:tap];
[tap.rac_gestureSignal subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
NSLog(@"%@",x);
}];
複製代碼
TestModel *model1 = [[TestModel alloc] init];
model1.age = 1;
model1.height = 11;
TestModel *model2 = [[TestModel alloc] init];
model2.age = 2;
model2.height = 22;
TestModel *model3 = [[TestModel alloc] init];
model3.age = 3;
model3.height = 33;
NSArray *array = @[model1,model2,model3];
[array.rac_sequence.signal subscribeNext:^(TestModel * _Nullable x) {
NSLog(@"%d",x.age);
}];
複製代碼
NSDictionary *dict = @{@"name":@"凡幾多",@"age":@"20",@"sex":@"男"};
[dict.rac_sequence.signal subscribeNext:^(id _Nullable x) {
//元祖
NSLog(@"%@",x);
RACTwoTuple *tuple = (RACTwoTuple *)x;
NSLog(@"key == %@ , value = %@",tuple[0],tuple[1]);
}];
複製代碼
NSTimer *timer = [NSTimer timerWithTimeInterval:30.0 target:self selector:@selector(timerFired:) userInfo:nil repeats:YES]; // 須要加入手動RunLoop,須要注意的是在NSTimer工做期間self是被強引用的
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; // 使用NSRunLoopCommonModes才能保證RunLoop切換模式時,NSTimer能正常工做。
中止計時器
- (void)stopTimer {
if (_timer) {
[_timer invalidate];
}
}
複製代碼
- 主線程
[[RACSignal interval:2.0 onScheduler:[RACScheduler mainThreadScheduler]]subscribeNext:^(NSDate * _Nullable x) {
NSLog(@"%@",x);
NSLog(@"%@",[NSThread currentThread]);
}];
- 子線程
[[RACSignal interval:2.0 onScheduler:[RACScheduler schedulerWithPriority:RACSchedulerPriorityHigh name:@"abc"]] subscribeNext:^(NSDate * _Nullable x) {
NSLog(@"%@",[NSThread currentThread]);
}];
複製代碼
參考文章 利用柵欄函數完成任務的調度post
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
TestModel *model1 = [[TestModel alloc] init];
model1.age = 1;
model1.height = 11;
TestModel *model2 = [[TestModel alloc] init];
model2.age = 2;
model2.height = 22;
TestModel *model3 = [[TestModel alloc] init];
model3.age = 3;
model3.height = 33;
NSArray *array = @[model1,model2,model3];
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.concurrent", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"🔞 START: %@", [NSThread currentThread]);
dispatch_async(concurrentQueue, ^{
[array.rac_sequence.signal subscribeNext:^(TestModel * _Nullable x) {
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"%d",x.age);
}];
}); // ⬅️ 任務一
dispatch_barrier_async(concurrentQueue, ^{ sleep(3); NSLog(@"🚥🚥 %@", [NSThread currentThread]);}); // ⬅️ Barrie 任務
dispatch_async(concurrentQueue, ^{ NSLog(@"111");}); // ⬅️ 任務四
NSLog(@"🔞 END: %@", [NSThread currentThread]);
}
複製代碼