如何在iOS中优雅的处理网络请求

在iOS开发过程中,如何为UIViewController瘦身是一个常见并且复杂的问题。为什么常见?如果没有精心的设计,UIViewController很容易变成很厚重、冗余。为什么复杂?在真实的项目中,都有各自的历史问题,要在现有的代码中瘦身是个非常有挑战的工作。

其实所谓的瘦身,核心就是要单一职责,这个跟面向对象的设计一样。像MVVM也是将之前UIViewController中处理的工作转换到其它的对象中。

在移动端开发的过程中,总是避免不了请求各种网络接口,这是移动App的特点。那么与网络接口交互的代码是一个界面的重要组成部分,这些部分完全可以独立成单独的层。而这些网络接口的请求和处理也都有自己的业务逻辑。

那么应该如何把网络接口交互的代码独立出来呢?我的答案是把单个接口封装成单独的类,这个类接收请求的参数,处理接口返回的结果。在PP的时候就已经在实践这种模式了,效果还不错。在最近的项目中,通过整合AFNetworkingMantle这2大常用库,完成了最新的网络框架GQDataController,她可以自动的将接口返回的JSON转成Mantle对象。项目地址见:https://github.com/gonefish/GQDataController

下面我们将通过一个例子来描述如何使用GQDataController将网络请求处理的代码封装成单独的类。

要开始使用GQDataController,必须先创建自己的子类,就像你继承UIViewController一样。

.h文件

@interface BasicDataController : GQDataController

@property (nonatomic, strong) NSString *ip;

@end

你可以添加自定义的属性,用于保存接口返回的结果。

.m文件

@implementation BasicDataController

- (NSArray *)requestURLStrings
{
    return @[@"http://httpbin.org/ip"];
}

- (void)handleWithObject:(id)object
{
    [super handleWithObject:object];
    self.ip = [object objectForKey:@"origin"];
}

@end

requestURLStrings用于返回请求接口的地址,支持多个地址备用。子类重写handleWithObject:方法,并将返回的JSON对象赋值给实例属性。

在ViewController中创建实例,然后调用request开始请求(默认是GET请求,子类可以重写requestMethod来进行修改)最后通过Delegate方法处理结果,非常简单清晰的流程。


- (void)viewDidLoad {
    [super viewDidLoad];

    self.basicDataController = [[BasicDataController alloc] initWithDelegate:self];

    [self.basicDataController request];
}

- (void)dataControllerDidFinishLoading:(GQDataController *)controller
{
    self.label.text = [NSString stringWithFormat:@"IP: %@", self.basicDataController.ip];   
}

对UIViewController来说,它并不需要知道请求的是什么接口和如何处理结果。这种模式与MVVM类似,但服务的对象稍微有点区别。所以,你可以在老代码中使用这种模式,也可以与ViewModel一起使用。

上面的例子只是GQDataController的基本使用,在对接口的结果处理上是采用手动保存的。GQDataController另外一个非常重要的功能是提供了对Mantle的支持,你可以自动的将返回的JSON结果转换成指定的Mantle对象。

你只需要在.m文件中添加如何代码

- (Class)mantleModelClass
{
    return [IP class];
}

mantleModelClass返回用于转换成Mantle的类型,IP是一个Mantle子类。另外,子类也不需要重写handleWithObject了。

在ViewController中修改Delegate方法的内容

- (void)dataControllerDidFinishLoading:(GQDataController *)controller
{
    self.label.text = [NSString stringWithFormat:@"IP: %@", self.basicDataController.mantleObject.origin];   
}

GQDataController会将转换的结果保存在mantleObject和mantleObjectList中。如果转换的JSON是字典对象会保存在mantleObject中,如果是数组对象则会保存在mantleObjectList中。

@property (nonatomic, strong, nullable) __kindof MTLModel<MTLJSONSerializing> *mantleObject;

@property (nonatomic, strong, nullable) NSMutableArray<__kindof MTLModel *> *mantleObjectList;

GQDataController还提供了分页、DataSource、接口重试、接口Stub的支持,更多使用可以参考项目的Demo

通过使用GQDataController,强迫你把所有的接口都从UIViewController中分离出来,一方面减少了UIViewController的负担,另一方面也提高了接口对象的复用程度。而且,集成GQDataController非常简单,对现有代码模式影响非常小,你可以轻松的转换过来。

最近的这篇文章《 猿题库 iOS 客户端架构设计》也提到了类似的解决方案。

OS X上的Vim

Vim是一种非常有用的工具,习得之后会极大的提升你敲键盘的速度。当然,编辑器之神也不是浪得虚名,Vim本身是非常强大的,这里就不一一举例了。自行搜索《Vim 用户手册中文版》学习。

在OS X上,有多种Vim可以选择

VimR是一个新项目,口号是“Refined Vim Experience for OS X”,其它都是比较老牌的项目。

除了Vim编辑器外,许多IDE或编辑器都支持Vim的键盘绑定,这样你可以在喜欢的开发工具上使用Vim来提高你的开发效率。

作为一个Xocde使用者来说,XVim是个非常好用的插件。

使用Launch Screen的坑

从iOS 8开始,可以使用XIB来制作启动页,这给了我们另外一种选择。

如果你的App已经开始使用XIB来做启动页,那么最好不要回退到设置启动图片的模式。因为这时系统很可能会缓存你原来的XIB界面:(,这样会看到2个启动界面闪现的问题。只有在用户删除App,重新安装才能解决。

2011.3.8 ~ 2014.10.31

2010年未的时候我做了一个决定,要离开工作多年的武汉。在自己独自做了半年App后,发现要做出一款成功产品并非那么简单,所以我要去业界前沿的地方。2011年后开始物色工作机会,北上深都是考虑的范围。非常有意思的是,当时过年没多久我还在家休息,接到PPTV的电话面试,之后在回武汉的路上接到了人事的电话。这样我就从武汉来到了上海,上海应该是这几个城市最优先的选择吧。另外,当时也没确定到底去哪个城市,如果没有这个机会估计会去北京吧。

在这三年多的时间里,观察到公司一系列的变化 还是非常有意思的。当公司拿到投资后,开始疯狂的乱花钱,当发现问题时,已经浪费了很多资源及时间。公司膨胀后造成了产品结构的复杂,反倒是多终端保持着小而快的团队。我觉得这里有个战略失误,此时正是发展移动端的好机会,但却花大资源搞Web端,丢掉了弯道超车的机会。除此之外,在很多其它问题上也没有很好的处理,终究是个二流公司吧。

非常幸运的是,工作这么多年来,都能结识到非常好的同事。在这三年多时间里能与大家一起共事非常赞。

上海 西安 华山游

今年的爬山计划最终锁定华山,11月头赶在工作的间隔去爬了华山,顺便也去西安转了一圈,整个行程花了4天的时间。

这里简要记录这次行程的,也可以给从上海过去的朋友一个参考。

如果只去华山的话,就直接坐Z92吧;要是想去西安转转,那交通工具选择就很多了,除了Z92外,还有D306和各种航班可选了。飞机的降落点是咸阳国际机场,离西安市中心大概1个小时车程吧。注意:Z92停靠西安站,D306停靠西安北站,机场大巴有直达西安北站的线,大概25分钟。

西安的旅游介绍可参考马蜂窝上这篇文章:西安人带你“西安6日游”(含华山)

西安闯红灯的行为好严重,这里的次序问题还是比较明显的。我对西安的感觉:雅俗共赏。

从西安去华山的火车有很多选择,但建议还是提前买好票。

我这次爬山选择的是一条徒步线路,简单的说就是从 玉泉院 -> 北峰 -> 东峰 -> 中峰 -> 南峰 -> 西峰。D1在东峰住宿,然后D2早上起来看日出(当时是7点的日出),看完日出接着出发,大概中午11点可到达西峰,然后坐西峰的缆车下去。没记错的话,到西峰就只能坐缆车下去(价格不菲,140的缆车 + 40的巴士),也可以从北峰步行下山或者乘北峰的缆车。虽然也可以原路从玉泉院下山,但这个线路实在是太远了(从玉泉院到北峰,我大概花了6个小时,北峰到东峰1个多小时)。其实先到西峰也不错,然后第2天从北峰下山。

还有一种夜爬线路到达北峰,这可以省略一晚的住宿费用,山上最便宜的床位是150 RMB 左右/人,没有洗澡的地方,甚至开水都是有限的。吃的也不便宜,一碗番茄鸡蛋面48 RMB,如果体力够可以自己多背点吃的。

2天时间可以很完整的体验华山,如果时间只有1天那就直接缆车上下吧。

回程的火车票最好提前订好,当天下山再去订火车票有点悬。甚至从华山回西安的票有时也会比较紧张,我就中标了,下山后只能买到20点后的票。这种情况可以选择坐汽车回西安,大概会花3个小时。我坐的汽车是到达了一个叫纺织枢纽站的地方,西安地铁1号线的终点站也在这里。坐地铁可以到达西安北站,然后可以在西安北站坐去咸阳国际机场的巴士。机场巴士的位置是从西安北站南广场出来一直走,看到马路后向右转,过一个红绿灯后会有一个公车站,再往前面走一点就会看到机场巴士的牌子了。

在外面旅游最好先把行程预定好,但还要留点缓冲的时间。

有批判文革的片子是好事

像我这代人对文革的认识太模糊,有时会听父母说到些,但还是没有清晰的认识。今天去看《归来》算是让我对文革有了更感性的认识。电影中的故事估计也只是那段历史的一小块,真实应该更加残酷。文革这个事情太奇怪了,我估计大多数正常的国家都无法理解。

所以皇帝是不靠谱的,他始终是个人,难免在神和魔之间徘徊,治国还是要靠制度。管理皆如此吧。

2181150064.jpg

Alone

上个月里读了一本某心理学的书,这本书不仅解释了我之前的错误,也让我失去了更多的信心,这真是沮丧的到底,甚至时刻都在刺痛着我。好在终于让我了解了这其中的真相。

最近的心情确实很差,为什么会变成这样?很明显我已经失控了,容易生气,脾气暴躁,从生气中发泄。

对于不信教的我,这真是非常难受。好在最近在读《活法》这本书,这里面所讲述的“道”就像是《道德经》的实践。

有时候人总是跟自己过不去,这时还是要及时调整,避免钻牛角尖。

免费私有Git仓库好地方Bitbucket

09年搞Python的时候,对HGGit更有兴趣,那时候 Bitbucket 提供了和 GitHub 类似的服务,但版本库是HG。随着Git日渐流行,Bitbucket 也开始提供Git的支持,后来Atlassiann收购了 Bitbucket。

Bitbucket 现在提供的收费服务与用户有关,跟仓库个数完全没有任何关系,私有和公开的都行。而5个用户是免费的,所以非常适合做个人私有仓库。有了Atlassiann的支持,服务肯定有保障。

被上了一课

尽然在而立之年的几天后被上了一课,这让我如何是X呢。

课的内容本来我是有机会提前看到,但命运的安排让我错过了,继续做了减分的事情,或许本来就已经不及格了。这几天一直在补课,有时候觉得科学真的是好事吗?了解太多也不一定是好事,多一分认识,那生活的选择又多了寸。这类平常的事情都已经发展出了理论,这到底是有人性还是没有人性我不懂。

虽然如此,但还是有许多反省的东西,这样又有了其它的角度来观察人生。一直没有意识到我是在浪费资源,造成了可能的损失。现在这个时代有了更多的选择,假如都付出了很大的代价才达到了和谐,那谁都没有对未来抱怨的权力。不过,最终还是取决于个人的价值观。已经好久没有折腾了,如果能从这套理论的夹缝里发展出新的业务那也不错。

在极短的时间内,碰到2件最有可能改变人格的事情,果然今年有点难过。最近视力有点下降…换个屏幕更好的本吧。今年旅游坐标:西、西南和…

 

iOS技术文章

为了收集和分享iOS的技术文章,我在Github上创建了iOSArticle项目,按时间收集优秀的技术文章。

https://github.com/gonefish/iOSDevArticle

2014年

2月

2013年

12月

11月

10月

9月

8月

7月

6月

5月

4月

2012

11月

5月

2011

5月