ReactiveCocoa简单实战 一

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则在收到错误信号后……呃……打印了那个错误……

这么快就没了

恩……男人是不是不能这么快……好吧,这次先写到这儿,好困啊,明天项目正式动工,先早点休息了。

下次为大家继续新建路线中的内容。(其实和这个用法大同小异)

代码写的到不到的还请多多包含,最好能帮忙指出错误!小弟谢过了。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom