AsyncDisplayKit近一年的使用体会及疑难点

一个第三方库能做到像新产品一样,值得大家去写写使用体会的,并不多见,AsyncDisplayKit却完全可以,因为AsyncDisplayKit不仅仅是一个工具,它更像一个系统UI框架,改变整个编码体验。也正是这种极强的侵入性,导致不少听过、star过,甚至下过demo跑过AsyncDisplayKit的你我,望而却步,驻足观望。但列表界面稍微复杂时,烦人的高度计算,因为性能不得不放弃Autolayout而选择上古时代的frame layout,令人精疲力尽,这时AsyncDisplayKit总会不自然浮现眼前,让你跃跃欲试。

去年10月份,我们入坑了。

当时还只是拿简单的列表页试水,基本上手后,去年底在稍微空闲的时候用AsyncDisplayKit重构了帖子详情,今年三月份,又借着公司聊天增加群聊的契机,用AsyncDisplayKit重构整个聊天。林林总总,从简单到复杂,踩过的坑大大小小,将近一年的时光转眼飞逝,可以写写总结了。

学习曲线

先说说学习曲线,这是大家都比较关心的问题。

跟大多人一样,一开始我以为AsyncDisplayKit会像RxswiftMVVM框架一样,有着陡峭的学习曲线。但事实上,AsyncDisplayKit的学习曲线还算平滑。

主要是因为AsyncDisplayKit只是对UIKit的再一次封装,基本沿用了UIKitAPI设计,大部分情况下,只是将view改成nodeUI前缀改为AS,写着写着,恍惚间,你以为自己还是在写UIKit呢。

比如ASDisplayNodeUIView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let nodeA = ASDisplayNode()
let nodeB = ASDisplayNode()
let nodeC = ASDisplayNode()
nodeA.addSubnode(nodeB)
nodeA.addSubnode(nodeC)
nodeA.backgroundColor = .red
nodeA.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
nodeC.removeFromSupernode()

let viewA = UIView()
let viewB = UIView()
let viewC = UIView()
viewA.addSubview(viewB)
viewA.addSubview(viewC)
viewA.backgroundColor = .red
viewA.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
viewC.removeFromSuperview()

相信你看两眼也就摸出门道了,大部分API一模一样。

真正发生翻天覆地变化的是布局方式,AsyncDisplayKit用的是flexbox布局,UIView使用的是Autolayout。用AsyncDisplayKitflexbox布局替代Autolayout布局,完全不亚于用Autolayout替换frame布局的蜕变,需要比较大的观念转变。

flexbox布局被提出已久,且其本身直观简单,较容易上手,学习曲线只是略陡峭。

这里有一个学习AsyncDisplayKit布局的小游戏,简单有趣,可以一玩。

整体上两天即可上手,无须担心学习曲线问题。

查看更多

分享到 评论

iOS两个客户端代码复用小技巧

一般一个App只有一个客户端,因此也只有一份代码仓库,也就无所谓复用不复用。但两个客户端也不是没有,美团、饿了么等就分商家版和买家版,贝聊App也分为老师版和家长版两个客户端。有两个客户端代码复用就在所难免,比如基本的工具类,比如一些共用的业务。本文就以贝聊App为例,分享当有两个客户端时代码复用的小技巧。

repository仓库划分

贝聊APP远程仓库划分为三个,一个家长端repository,一个老师端repository,一个两端共用的BLKit repository

家长端的本地repository包含远程的家长端repository和两端共用的Kit repository
老师端的本地repository包含远程的老师端repository和两端共用的Kit repository


查看更多

分享到 评论

生命的惯性

生命好似被上帝精心编排的话剧,年少时学习,长大了工作,然后结婚生子,抚养小孩,照看父母,最后垂垂老去。一幕接着一幕,一幕赶着一幕。貌似自由意志,其实我们只有润色生活这么一点点权限。

而在某一幕中,比如工作,我们也只是尽己所能完成每一日的事情。当然随着日复一日,年复一年,薪水逐年递增,职位越干越大,工作内容也渐进宏观。从小白程序员,到编程资深程序员,到项目负责人,到CTO。没有什么会一成不变,但也没有什么会突如其来。

循序渐进,是我们的一生,也是我们的每一天,每一秒,循序渐进就是我们生命的惯性。

这没啥不好,途中会有焦虑,会有进步,会有责罚,会有掌声,会有层出不穷的新事物。但总觉得有点烦闷,因为一切都是可期的。

我们渴望着惊喜,因为惊喜让生命充盈、丰厚。

或在某个小巷,遇到一个丁香一样的姑娘,或在某个不经意的抬头,看见散落满天的星,或在某次与人会谈时,获得生命的顿悟,或在举步维艰之际,遇到一生的贵人。

生命难逃惯性,我们总期望着惊喜。惊喜也总会不期而至,但并不是无缘无故。今日生命的惊喜大多是我们昨日努力种下的种。

所以当此刻想起什么非常想做最终却不曾开始的事,努力开始吧,不因资源匮乏,不因能力欠缺,不因自卑,不因懒惰,不因忙碌。殊不知。我们内心真实的渴望,才是生命的惊喜汩汩不穷的源泉。

有时偷懒一件事,错过一生。

有时多做一件事,繁华一世。

细思之,人生其实是一条幽闭狭窄只有一个出口的通道,由着生活的惯性总会到达不出意外的终点,只有勇敢坚定的尝试新事物,才能从坚硬的道壁上凿出细微的裂痕,看到另外一个方向的光,甚至改变整个通道的方向。

所以我才会坚持周更博客,虽然我不知道这会带我去到哪里,但我知道,不写生活一如往常,坚持了它总会带我去想去的地方。

“Life is like a box of chocolates. You never know what you’re gonna get.”

阿甘说生活就像一盒巧克力,你永远不知道下一块是什么味道。

但生命的惯性,是一个编写良好的黑白滤镜,抹去了生活的五彩缤纷,唯有珍惜每一个心动的瞬间,努力埋下惊奇惊喜的种子,或许你的一生才会凑够那一盒巧克力所有的味道。

分享到 评论

commit和branch理解深入

深入理解gitcommitbranch,有助于在日常开发中,更好的运用git

commit的本质

初始化目录

为便于讲解,先创建一个如下目录结构的BeiLiao(贝聊是我所在的公司)目录:

在命令行中输出文件的目录结构如下:

1
2
3
4
5
6
7
~ qingmo$: tree
.
└── BeiLiao
├── Component
│   └── App.js
├── index.html
└── index.js

如果以竖向文件层级树的样式看是这样的(深色表示文件目录,浅色表示文件),

其中App.jsindex.htmlindex.js都填充了相应的内容。

初始化git并提交第一个commit

先初始化git,然后添加所有文件到git的暂存区,成功后提交一个commit,最后log一下版本历史记录:

1
2
3
4
5
6
7
8
9
10
11
~ qingmo$: cd ~/../BeiLiao(切换到BeiLiao这个文件目录)
~ qingmo$: git init
~ qingmo$: git add .
~ qingmo$: git commit -m “init project”
~ qingmo$: git log

commit 5bb33508dd4f00dd4d63c6e28546e044ebb51ac0
Author: qingmo <qingmo@163.com>
Date: Sun Mar 26 15:18:01 2017 +0800

init project

查看更多

分享到 评论

《结构型设计模式》之iOS系统框架实践

结构型设计模式是从程序的结构上解决模块之间的耦合问题,主要包括适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式和代理模式等7种经典设计模式,在iOS系统框架中组合模式、装饰器模式和享元模式是有经典实现的,而适配器模式、桥接模式、外观模式和代理模式iOS系统框架中的实现并不明显,但在第三方框架或者贝聊(我所在的公司)的App是有用到的,为便于讲解,本文会挑选最恰当的例子。

本文是设计模式之iOS系统框架实践系列中的第二篇(总共三篇),如果您对《创建型设计模式》感兴趣,建议看看我的前一篇文章《创建型设计模式》之iOS系统框架实践

适配器模式(Adapter)

适配器模式是将一种接口,转换成另外一种接口,一般被适配的类的功能与外界所希望的一致,只是接口与外界所希望的不同,所以需要适配接口。一般需要新旧接口的转换时用到。

不少资料上讲iOS中的delegate委托就是一种适配器模式,个人觉得太牵强。虽然将一个现有的类,扩展遵循指定delegate的协议,实现了接口的改变,但功能完全是新添加的,何来接口转换只说?(原来苹果官方资料说protocol就是适配器模式,也是醉了)

查看更多

分享到 评论

《创建型设计模式》之iOS系统框架实践

为了API的易用性、易维护性和健壮性,苹果工程师在iOS系统框架中其实运用了不少经典设计模式,而这些实践也正是因为良好的封装性,开发中我们虽日日相对,却也难以察觉它的存在。相对于其他生搬硬造隔靴搔痒的例子,这些我们熟悉的不能再熟悉的API方是学习设计模式的最佳案例。因此本系列拟以iOS系统框架中相关设计模式的实践为起点,探讨研究23种经典设计模式。

本文先讲述《创建型设计模式》(Creational Patterns)。

创建型设计模式是在创建一个类时用到的设计模式,总共有5种,其中工厂方法模式还可以根据实现的不同,分出简单工厂模式和工厂方法模式。

简单工厂模式(Factory Method)

iOS系统Foundation框架中的NSNumber所应用的就是简单工厂模式。

简单工厂模式主要解决不同情况下,需要创建不同子类,而这些子类又需要转化为公共父类让外界去使用的问题,因为这样对外接口只有一个,实际行为却因子类的具体实现而不同。拿NSNumber来说,传入IntFloatDoubleCharUnsignedChar等具体numberNSNumber返回的是对应的NSNumber子类,而我们使用时只知NSNumber,不知具体的子类。

1
2
3
4
5
6
7
8
9
import UIKit
let boolValue: Bool = true
let doubleValue: Double = 1.0

let boolN = NSNumber(value: boolValue)
let doubleN = NSNumber(value: doubleValue)

print(type(of:boolN))
print(type(of:doubleN))

输出结果为

1
2
__NSCFBoolean
__NSCFNumber

查看更多

分享到 评论

iOS触摸事件的流动

当指肚轻触屏幕,整个系统像沉睡的生灵突然被惊醒,然后经历过腥风血雨的一段奇幻旅行,最终又归于沉寂。

整个iOS触摸事件从产生到寂灭大致如下图:


查看更多

分享到 评论

如何在iOS开发中更好的做假数据?

当工期比较紧的时候,项目开发中会经常出现移动端等待后端接口数据的情形,不但耽误项目进度,更让人有种无奈的绝望。所以在开发中,我们常常自己做些假数据,以方便开发和UI调试。然而做假数据方法不同,效率和安全性都各不同,有时稍有不慎,还会产生很大的bug。因此本文拟结合我在贝聊的开发经验,讲一讲我们组在iOS开发中曾经用过的做假数据的方法及其优劣。

示例项目

为方便下文的说明,本文主要以贝聊家长版app发现首页的热门帖子列表的实现为例。热门帖子列表的样式如下图:

这是比较常见的列表,用常用的UITableView实现即可,但需要自定义一个的UITableViewCell的子类ExploreTableViewCell。项目中,ExploreTableViewCell并没有用xib实现(因为xib日后不好修改,且代码复用性差),而是通过SnapKit用纯代码布的局,具体的布局代码大致如下:

查看更多

分享到 评论

这一年与下一年-2016年度总结正式版

这一年

每当总结过去一年的时候,总感觉时间匆匆,一转眼又是一夏,一转眼又过一秋,时间流逝不止,我们只能以成长搪塞逐渐衰老的年华。

我是6月20日来到贝聊的,处于程序员小白水平的我,当时只能勤奋的追赶,努力的做些小项目练手,同时也疯狂的补齐残缺的编程知识。半年以后到今天,积累起来,完成的项目大大小小,林林总总,也有一二。如网络日志feature、班级列表刷新、老师端班级语音播报、家长端老师端发现改版及再改版、老师端和家长端好习惯首页和详情页、弹窗基础框架、优惠券详情页和帖子详情红包页、一系列小的工具拓展、大图浏览、客服、专属客服、客服评价等等。我是一个不喜欢拖累大家的人,不愿意大家因为我的原因出现拖延,因此这些项目大部分如时的交付,而且作为初学者,写代码时如履薄冰战战兢兢的,千般思虑,万般测试,因此上线后的bug并不多见,整体还算优良。

其实回想起这段日子,我能分明的感受到自己对编程的认识是一个层次一个层次的成长,每做一个大的feature项目,基本就会遇到一个大的问题,然后就向前进一步。

记得我正式做的第一个独立feature是语音播报,迅速的写完UI,连通API后,随便测试一下就上线了,当时心里极其地没底,强烈地感觉代码能跑起来是随机的,我思考了很久也没找到让我心安地路径,但这个问题却一致残留在脑海,直到做了几个大的项目后,我才找到答案,那就是充分地自测和正确的开发流程,但是能做到这些也是在我解决其他同样让人苦恼的事之后了。

之后便接到了发现改版的feature,这个feature对我而言,是较新较重的,时间又非常紧迫,要5天后交货,我压力山大,当时我连怎么写请求,怎么发请求,怎么写model,怎么合理分离vc的职责等都还不懂,收到设计后,便立即动起手来实现UI,想着不懂的边写边学,疯狂5天后,不懂的真的都依葫芦画瓢地大概懂了,但是却不出意料的没有跟上进度,但谁曾料第五天上午突然接到消息说项目取消了,劫后余生我仰天长笑,不过做项目中有一朵巨大的乌云让我很烦恼,即如何处理UI更新与数据更新的耦合逻辑,我翻看了其他员工的部分代码,数据的流动杂乱不堪,UI更新随意罗列,就像在悬崖边飙车,刀锋上跳舞,看的我心惊肉跳。在苦思无解之际,有一天突然听到子豪极其推崇react的单向数据流,我灵机一动,突然意识到每一个VC的数据都可以看成这个VC的状态,而UI只是状态的表现,更新UI应该在更新状态之后,而状态更新应该集中处理,几番思考后,我确定这是个不错的想法。

于是很快,发现改版又启动了,世事变幻真是让人来不及定睛一看,这次我推翻了以前的逻辑架构,开始试验局部单向数据流动的想法,把dataSource更名为stateSource(现在想想正确的叫法应该为stateStore),把stateSource中所有model名都更改为state(现在想想应该所有的model类都应该更名为state),每一个state的状态都有一个对应的修改方法,在修改后利用stateSource持有的vc直接更新UI,而如果某一状态需要更新,直接调用相应状态的更新方法即可。这样,整个数据流动和UI更新就极其的清晰。现在想想这其实就是MVVM的思想,只不过我这里没有UI和数据的自动绑定。但在应用中,发现页面的状态并不多,局部单向数据流的优势发挥的并不明显,所以在后面的业务开发中,我并没有刻意把model名改为state,只是劫取了核心思想。

查看更多

分享到 评论

青葱年华-2016年度总结随写版

仔细端详着年初许下的誓言,孤零零的转行二字高悬,简单的有点简陋,隐藏了背后所有的心酸。

2015年下半年,我紧闭着双眼,静静凝视着自己的灵魂,发现多年浸润土木,灵魂却渐渐干瘪了,随处可见的疮痍,应该是多少次默默承受苦痛,留下的伤疤,慢慢溃烂。不转行不行了,多次探索寻觅,最终走上了编程这条又臭又烂的不归路。数不清多少个通宵达旦的刻苦修炼,也不知道多少个无休无止的知识学习,2015年初,终于许下来年开始找工作的誓言和宏远。

2016年上半年,草草应付了绘图工作,我开始奔波各大招聘网站,每天早上固定投简历,不拒绝任何一个面试,哪怕公司再小。三月去了,四月走了,五月也只是简单打了个照面,我等的offer却不见,零星的面试,去了又回,失落的情绪,破碎的幻想,绝望从一点点逐渐累积到汹涌迷漫。绝望到头了,我就开始幻想,幻想着有一家大公司要我,然后我踏踏实实的跟着团队学习,一开始肯定做不了什么大的贡献,但因为自己的努力,渐渐的真的成为公司不可或缺的一名优秀程序员。。。幻想着,幻想着,连幻想都没了。都6月了,该投的已经投了,未见offer的一点踪迹,仅有的几个面试中,面试官还苦口婆心的劝我别转,有的还说想跟我对调。看来iOS容不下我这个大才,于是6月中旬,我又重新调整了方向,开始向数据挖掘进发,回家在iPad中下载了十几本书,又开始了无休无止不知疲倦的学习。但就在这时,佛祖观世音菩萨太上老君孔圣人关二爷耶稣基督穆罕默德真主显灵了,迄今为止面过我公司中最大的贝聊竟然发来了offer,我勒个天,命运这是几个意思,这么照顾我?这么折磨我?我卷起铺盖就去了!

对于转行人,最难的就是有人愿意给机会,一旦有,他们一定能抓住,因为他们想的更明白,看的更透彻,没有其他人的游移不定和躁动不安,他们会十分努力!

查看更多

分享到 评论