加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

reactiveCocoa学习

发布时间:2020-12-15 05:27:56 所属栏目:百科 来源:基本都是从这些文章上摘录来的。
导读:ReactiveCocoa学习 看了好些天了,老是迷迷瞪瞪的,写下来,比较,分析一下。 这是一些参考网站:基本都是从这些文章上摘录来的。。 http://blog.163.com/l1_jun/blog/static/1438638820142610349839/ http://www.cocoachina.com/applenews/devnews/2014/011

ReactiveCocoa学习

看了好些天了,老是迷迷瞪瞪的,写下来,比较,分析一下。

这是一些参考网站:基本都是从这些文章上摘录来的。。

http://blog.163.com/l1_jun/blog/static/1438638820142610349839/

http://www.cocoachina.com/applenews/devnews/2014/0115/7702.html

http://blog.segmentfault.com/erliu/1190000000408492

首先:是一些概念。

reactiveCocoa,是用来统一处理响应的一个框架。网上看来的就是:ative app有很大一部分的时间是在等待事件发生,然后响应事件,比如等待网络请求完成,等待用户的操作,等待某些状态值的改变等等,等这些事件发生后,再做进一步处理。 但是这些等待和响应,并没有一个统一的处理方式。Delegate,Notification,Block,KVO,常常会不知道该用哪个最合适。有时需要chain或者compose某几个事件,就需要多个状态变量,而状态变量一多,复杂度也就上来了。为了解决这些问题,Github的工程师们开发了ReactiveCocoa。

ReactiveCocoa试图解决什么问题
传统iOS开发过程中,状态以及状态之间依赖过多的问题
传统MVC架构的问题:Controller比较复杂,可测试性差
提供统一的消息传递机制


RACSignal对象捕捉当前和未来的值。信号可以被观察者链接,组合和反应。信号实际上不会执行,直到它被订阅。


RACObserve使用了KVO来监听property的变化,只要观察的值被自己或外部改变,block就会被执行。但不是所有的property都可以被RACObserve,该property必须支持KVO,比如NSURLCache的currentDiskUsage就不能被RACObserve。KVO现在还不了解。MARK一下。。回头看。

[RACObserve(self,self.testLabel.text) subscribeNext:^(id x) {
NSLog(@"%@",@"testlabel");
}];

监听self.testlabel.text,如果text有变化,就执行nslog方法。

代码意思就是观察self.testLabel.text....

// [RACAble(self.testLabel.text) subscribeNext:^(id x) {
// NSLog(@"%@",@"testLable");
// }]; 作用和下面这个一样,不知道区别。。但是这个有个警告。


//把testString,self.testLabel.text观察合并起来,其中有一个值发生变化,就调用reduce中的方法。return的值会传到subscribeNext中。也就是说:number *x的值是SSSS。

次方法就是signal的的合并。

[[RACSignal combineLatest: @[RACObserve(self,testString),RACObserve(self,self.testLabel.text)]
reduce:^id(NSString *string,NSString *fieldString){
NSLog(@"str: %@,field: %@",string,fieldString);
return @"SSSS";
}]
subscribeNext:^(NSNumber *x) {
NSLog(@"X Class: %@",x);
}];

//下面这个是对上面的一个运用。返回的值会被付值给loginbutton.enabel。

RAC(self.logInButton,enabled) = [RACSignal
combineLatest:@[
self.usernameTextField.rac_textSignal,
self.passwordTextField.rac_textSignal,
RACObserve(LoginManager.sharedManager,loggingIn),
RACObserve(self,loggedIn)
] reduce:^(NSString *username,NSString *password,NSNumber *loggingIn,NSNumber *loggedIn) {
return @(username.length > 0 && password.length > 0 && !loggingIn.boolValue && !loggedIn.boolValue);
}];



UIButton *btn1 =[UIButton buttonWithType:UIButtonTypeInfoDark];
[btn1 addTarget:self action:@selector(btnClick1:) forControlEvents:UIControlEventTouchUpInside];
[btn1 setFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-10,[UIScreen mainScreen].bounds.size.height/2+20,20,20)];

//按钮被点击的时候会调用下面方法,执行在btnClick1:之后。
btn.rac_command =[[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"按钮被点击,signal");
return [RACSignal empty]; //为毛返回RACSignal empty啊,有什么用。。。要不是返回空,怎么处理?求教。。


}];


// Notification
[[[NSNotificationCenter defaultCenter]
rac_addObserverForName:UIKeyboardDidChangeFrameNotification
object:nil]
subscribeNext:^(id x) {
NSLog(@"键盘Frame改变");
}
];

signal创建完了,如何获取信号,如何处理信号?

//这是网上看的。

冷信号(Cold)和热信号(Hot)
上面提到过这两个概念,冷信号默认什么也不干,比如下面这段代码
RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
NSLog(@"triggered");
[subscriber sendNext:@"foobar"];
[subscriber sendCompleted];
return nil;
}];

我们创建了一个Signal,但因为没有被subscribe,所以什么也不会发生。加了下面这段代码后,signal就处于Hot的状态了,block里的代码就会被执行。
[signal subscribeCompleted:^{
NSLog(@"subscription %u",subscriptions);
}];

//创建信号的另一种方式

RACSignal *abc =[@"A B,C D" componentsSeparatedByString:@","].rac_sequence.signal; //componentsSeparatedByString:@",“按@”,“对字符进行分割

[abc subscribeNext:^(NSString *x) {
NSLog(@"abc:%@",x);
}];

UIView Categories
常用的UIView也都相应的category,比如UIAlertView,就不需要再用Delegate了。

UIAlertView *alertView =[[UIAlertView alloc]initWithTitle:@"" message:@"" delegate:nil cancelButtonTitle:@"A" otherButtonTitles:@"B",@"C",nil];
[[alertView rac_buttonClickedSignal] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[alertView show];


网上的:再说一下UITableViewCell,RAC给UITableViewCell提供了一个方法:rac_prepareForReuseSignal,它的作用是当Cell即将要被重用时,告诉Cell。想象Cell上有多个button,Cell在初始化时给每个button都addTarget:action:forControlEvents,被重用时需要先移除这些target,下面这段代码就可以很方便地解决这个问题:

[[[self.cancelButton
rac_signalForControlEvents:UIControlEventTouchUpInside]
takeUntil:self.rac_prepareForReuseSignal]
subscribeNext:^(UIButton *x) {
// do other things
}];


//这个不是很理解。。。。。

NSObject+RACLifting.h
有时我们希望满足一定条件时,自动触发某个方法,有了这个category就可以这么办
- (void)test
{
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW,(int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime,dispatch_get_main_queue(),^(void){
[subscriber sendNext:@"A"];
});
return nil;
}];

RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"B"];
[subscriber sendNext:@"Another B"];
[subscriber sendCompleted];
return nil;
}];

[self rac_liftSelector:@selector(doA:withB:) withSignals:signalA,signalB,nil];
}

- (void)doA:(NSString *)A withB:(NSString *)B
{
NSLog(@"A:%@ and B:%@",A,B);
}

这里的rac_liftSelector:withSignals 就是干这件事的,它的意思是当signalA和signalB都至少sendNext过一次,接下来只要其中任意一个signal有了新的内容,doA:withB这个方法就会自动被触发

都至少sendnext一次什么意思。。signal怎么有新内容。。原谅我的逗比。。


NSObject+RACSelectorSignal.h
这个category有rac_signalForSelector:和rac_signalForSelector:fromProtocol: 这两个方法。先来看前一个,它的意思是当某个selector被调用时,再执行一段指定的代码,相当于hook。比如点击某个按钮后,记个日志。后者表示该selector实现了某个协议,所以可以用它来实现Delegate。

这个试了几个不知道怎么用。。。

[[self rac_signalForSelector:@selector(viewDidAppear:)] subscribeNext:^(id x) {
NSLog(@"viewDidAppear方法执行完毕,这个是挂钩");
}];

[[btn rac_signalForSelector:@selector(setFrame:)] subscribeNext:^(id x) {
NSLog(@"btn设置Frame");
}];

这种倒是可以。。


UIButton *btn =[UIButton buttonWithType:UIButtonTypeInfoLight];
[btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
[btn setFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-10,[UIScreen mainScreen].bounds.size.height/2-10,20)];
[self.view addSubview:btn];

[[btn rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
NSLog(@"btnClick挂钩");
}];

这种就逗比了。。。不能和button添加的按钮事件挂钩么。。。


//创建自己的RACSignal。但是怎么用啊。。。

-(RACSignal *)urlResults {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSError *error;
NSString *result = [NSString stringWithContentsOfURL:[NSURL URLWithString:@"http://www.devtang.com"]
encoding:NSUTF8StringEncoding
error:&error];
NSLog(@"download");
if (!result) {
[subscriber sendError:error];
} else {
[subscriber sendNext:result];
[subscriber sendCompleted];
}
return [RACDisposable disposableWithBlock:^{ //返回的不是Signal么,这disposable是什么玩意。。。
NSLog(@"clean up");
}];
}];

}


Mapping

-map:方法用来改变流中的值并用结果创建一个新的流:

RACSequence *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence;

// Contains: AA BB CC DD EE FF GG HH II
RACSequence *mapped = [letters map:^(NSString *value) {
return [value stringByAppendingString:value];
}];


Filtering

filter:方法用一个block来判断(test)每一个值,如果判断通过则把这个值加入到结果的流(resulting stream)中:

RACSequence *numbers = [@"1 2 3 4 5 6 7 8 9" componentsSeparatedByString:@" "].rac_sequence;

// Contains: 2 4 6 8
RACSequence *filtered = [numbers filter:^ BOOL (NSString *value) {
return (value.intValue % 2) == 0;
}];


Concatenating

-concat:方法将一个流中的值加到另一个中:

RACSequence *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence;
RACSequence *numbers = [@"1 2 3 4 5 6 7 8 9" componentsSeparatedByString:@" "].rac_sequence;

// Contains: A B C D E F G H I 1 2 3 4 5 6 7 8 9
RACSequence *concatenated = [letters concat:numbers];


Combining latest values

+combineLatest:以及+combineLatest:reduce:方法会观察(watch)多个信号的变化,然后在一个变化发生的时候向那些信号发送最新的值。

RACSubject *letters = [RACSubject subject];
RACSubject *numbers = [RACSubject subject];
RACSignal *combined = [RACSignal
combineLatest:@[ letters,numbers ]
reduce:^(NSString *letter,NSString *number) {
return [letter stringByAppendingString:number];
}];

// Outputs: B1 B2 C2 C3
[combined subscribeNext:^(id x) {
NSLog(@"%@",x);
}];

[letters sendNext:@"A"];
[letters sendNext:@"B"];
[numbers sendNext:@"1"];
[numbers sendNext:@"2"];
[letters sendNext:@"C"];
[numbers sendNext:@"3"];
注意:组合的信号(combined signal)只会在所有的输入至少都有一个值的时候才会发送它的第一个值,比如上面代码中@"A"没有被输出因为numbers还没有收到一个值。

RAC在应用中大量使用了block,由于Objective-C语言的内存管理是基于引用计数 的,为了避免循环引用问题,在block中如果要引用self,需要使用@weakify(self)和@strongify(self)来避免强引用。另外,在使用时应该注意block的嵌套层数,不恰当的滥用多层嵌套block可能给程序的可维护性带来灾难。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读