ReactiveCocoa简单实战
我厂广招各路大神加入:job.koudaitong.com
可以发简历到 tianchi@qima-inc.com O(∩_∩)O~
前戏
今天从杭州回家错过了高铁,又改成了客车。本来非常懊恼的心情,看到文章被SF博客转发了,一下子就好了起来。
最近闲着也是为了下一个与TX的小伙伴合作的项目做准备,做了一个简单的APP。主要的功能就是设定一个目的地,在你快要到达目的地的时候给你提醒。对于我这种坐动车常做过站的人来说,恩,时候是拯救自己一把了。
欲露还羞
项目的结构很简单,如下图所示:
项目使用了MVVM的框架结构来替代MVC框架。storyboard中的内容如下:
第一个界面为保存的路线,选择之后直接进入出发页面,新增路线之后点击出发同样进入出发页面。在出发页面中点击changeBtn(就是那个没显示全的按钮,恩,偷懒了
)可以修改提示音乐。出发页面中会计算当前位置与目的地的直线距离,以及估算的到达时间(现在APP里面好像算错了,正在改正
)
正戏开始
首先,将高德地图的SDK配置好之后,来看看第一个页面--ChooseViewController的内容:
#import "ChooseViewController.h"
#import "ChooseViewModel.h"
#import <AMapSearchKit/AMapSearchObj.h>
#import "OnRoadViewController.h"
#import <PromiseKit/PromiseKit.h>
@interface ChooseViewController ()
@property (nonatomic,strong) ChooseViewModel *viewModel;
@property (nonatomic,strong) NSDictionary *targetInfoDic;
@end
@implementation ChooseViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_viewModel = [ChooseViewModel new];
self.tableView.delegate = _viewModel;
self.tableView.dataSource = _viewModel;
[_viewModel.cellSelectedSignal subscribeNext:^(id x) {
if (x) {
//tiaozhuan
_targetInfoDic = x;
[self performSegueWithIdentifier:@"SelectToGo" sender:self];
}
}];
[_viewModel.loadRoutesFromCache subscribeNext:^(id x) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
} error:^(NSError *error) {
NSLog(@"%@",error.description);
}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:@"SelectToGo"]) {
CGPoint location = [_targetInfoDic[@"target"] CGPointValue];
NSDictionary *info = _targetInfoDic[@"target_info"];
AMapPOI *targetPoi = [[AMapPOI alloc] init];
AMapGeoPoint *mgp = [AMapGeoPoint locationWithLatitude:location.x longitude:location.y];
targetPoi.location = mgp;
targetPoi.name = info[@"name"];
targetPoi.address = info[@"address"];
targetPoi.type = info[@"type"];
OnRoadViewController *onRoadVC = (OnRoadViewController *)[segue destinationViewController];
onRoadVC.targetPoi = targetPoi;
}
}
@end
很简单的一段代码。在匿名类别中添加了两个对象,一个就是ViewModel,另一个用来储存目的地的经纬座标的字典。
在viewDidLoad
中,我们将tableview的delegate与dataSource都设为了刚刚new出来的viewModel。并且我们分别对viewModel中的cellSelectedSignal
信号与loadRoutesFromCache
信号绑定了next
的处理事件。
那么我们就来看看这两个事件到底是怎么起作用的吧。在ChooseViewModel
中,这两个信号分别是这样子的:
-(RACSignal *)loadRoutesFromCache;
@property (nonatomic,strong) RACSubject *cellSelectedSignal;
在对象被new的时候,我们实例化了cellSelectedSignal
信号:
+(id)new{
ChooseViewModel *model = [super new];
model.cellSelectedSignal = [RACSubject subject];
return model;
}
(不知道这样写有没有问题
)它一个RACSubject
对象,subject的特点就是信号的发送是可控的。下面就来看看这个信号是怎么可控的吧:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[self.cellSelectedSignal sendNext:self.waysDic[self.routesArr[indexPath.row]]];
}
我们使用了sendNext:方法将waysDic
中的路径信息通过信号发送了出去。在ChooseViewController
中注册的next处理事件便会得到执行。在其中,我们储存了目的地信息吼将页面push到下一个页面,在push之前我们构建了一个poi对象(高德SDK
),并传递了过去。
接下来看看那个从文件中读取内容的信号吧(loadRoutesFromCache
)。
-(RACSignal *)loadRoutesFromCache{
RACSubject *subject = [RACSubject subject];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSData *data = [NSData dataWithContentsOfFile:kWaysSavePath];
NSMutableDictionary *waysDic = [NSKeyedUnarchiver unarchiveObjectWithData:data];
if(waysDic!=nil && [waysDic allKeys].count>0){
self.waysDic = waysDic;
self.routesArr = [waysDic allKeys];
[subject sendNext:_routesArr];
[subject sendCompleted];
}else{
[subject sendError:[NSError errorWithDomain:@"rb.loadroutes" code:0 userInfo:@{@"error": @"未能加载"}]];
};
});
return subject;
}
这个信号被表示成了一个方法,这个方法返回了一个Subject对象。在异步执行完成后,向这个Subject对象发送next与completed信号,如果内容不存在则发送error信号。VC中(其实是view
)中的next处理事件在收到信号后回到主线程刷新tableview;error则在收到错误信号后……呃……打印了那个错误……
这么快就没了
恩……男人是不是不能这么快……好吧,这次先写到这儿,好困啊,明天项目正式动工,先早点休息了。
下次为大家继续新建路线中的内容。(其实和这个用法大同小异
)
代码写的到不到的还请多多包含,最好能帮忙指出错误!小弟谢过了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。