Onelong

分享知识,与你一起进步......
RSS icon Home icon
  • android找靓机二手手机2.2

    post by onelong / 2016-10-18 14:26 Tuesday [工作]

    8月份的时候发布了2.2版本,现在准备发布2.3版本了,8月份统计的时候,装机量30多万台,现在估计将近40w了,感觉不错。

    点击查看原图点击查看原图点击查看原图点击查看原图点击查看原图

    阅读全文>>

  • iOS内存泄漏排查

    post by onelong / 2016-10-17 15:18 Monday [工作]

    现在iOS开发中大部分都是用了自动引用计数器的,内存管理基本上是编译器帮我们处理了,唯一要自己的处理的就是循环引用。在网上有很多教程告诉我们该如何避免循环引用。如代理用weak修饰,block要类似__weak ViewController *weakSelf = self这样处理。我知道这些,大部分开发者都是懂的。但是很时候会忘记,或者想的不够多。例如 某ViewController持有AView和BView,而且AView是加在BView上的,这种情况很多时候是很难发现的,所以我们需要工具帮助我们排查。上次在Android上用了LeakCanary之后,查找内存泄漏,修复bug的效率高多了,这次还是一样,介绍一下iOS上面的工具-MLeaksFinder这个工具的介绍有很多,我就不多说了,我更关心的是如何用起来,最近一个项目,我小试牛刀,效果立竿见影。如果内存泄漏,会在控制台打印如下的信息
    *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Possibly Memory Leak.In case that MyTableViewCell should not be dealloced, override -willDealloc in MyTableViewCell by returning NO.
    View-ViewController stack: (
    MyTableViewController,
    UITableView,
    UITableViewWrapperView,
    MyTableViewCell
    )'
    那该怎样处理呢? 其实控制台的信息已经告诉我们了 MyTableViewCell should not be dealloced, override -willDealloc in MyTableViewCell by returning NO,重写MyTableViewCell的-(void)willDealloc方法,将里面引用外面的东西置为nil就好了。处理之后重新运行就不会再提示了。是不是很简单呢?工具帮助我们提高效率。
    还有一种情况是block的循环引用,这个是无法列出堆栈的。只能靠自己观察,在block使用weakSelf,还有一个值得主要的是例如某属性:
    @property (nonatomic,strongUILabel *titleLabel;
    而你在block里面这样使用了
    _titleLabel.text=xx
    这样也是不行的。但是这个我们很容易忽略。
    我觉得一个好的习惯就是在每个对象了里面都重写-(void)willDealloc,将全部属性都置为nil,这样就可以防范于未然了。虽然这个工具只能帮助我们检测ViewController上面的内存泄漏,但是通过修复bug可以更好的规范我们的代码。

  • iOS项目构建

    post by onelong / 2016-10-16 16:52 Sunday [工作]

     最近一直想写关于iOS项目构建的东西,突然来了一些bug和别的事情,忙打乱了大部分节奏。上上周就开始了解使用cocoapods搭建私有仓库了。在iOS开发中,一直说要模块化,很多时候我们认真模块化就是怎样分目录,对于小项目,的确是这样的。Xcode各方面的都不错的,唯一的遗憾就是在构建项目的太落后了,随便加一个文件都是入侵式的,放在项目里面的文件夹,还需要自己add到project里面。在多人协作里面,这样的方式冲突特别多。在很多大型项目构建工具里面,都不需要这样,如maven,gradle,makefile,cmake等,都是可以让每个人专注于自己的子模块,过程不需要修改总的项目文件。在iOS项目当然也是有办法的,如每个模块打包成静态库,每个模块打包成Framework,从iOS8开始,运行开发者使用动态库了,很多问题就冲突问题就不是问题了。以前使用静态库冲突问题依赖问题非常棘手,大部分都要依赖cocoapods来解决。有了动态库之后,很多模块的依赖问题就好解决了,例如A模块依赖K库,B模块也依赖K库,弄三个动态库就可以了,不会用冲突问题。但是静态库的话,就可以有麻烦了,在编译A模块的时候可能会静态把K库打包进来,同样B模块也会这样,到最后打包整个app的时候,可能就会报错了,app包含了两个K库的代码。使用动态库则不同,动态库是在运行时链接加载的,彼此都是独立的。自己手工创建静态库或者Framework,步骤繁琐,效率低下,容易出错。如果cocoapods很方便了,每个模块都是一个git库,提交代码之后,在代码编译的服务器上pod update,xcodebuild 就可以自动打包分发了。苹果的垃圾桶也可以这样,像tx的大型游戏,用macbook pro的顶配打包都知道要多少时间呢,需要苹果的垃圾桶。
    能利用cocoapods构建项目的前提是模块要组件化,需要想到一个方法,能到很方便的注册模块,加载模块。这些网上有很多方案,http://www.jianshu.com/p/afb9b52143d4 感兴趣的希望认真的demo一下,虽然并不是每个人都能接触大项目的,但是为未来做准备是必要的。我在git上的demo就是用了CTMediator+Target-Action方案,该方案比较适合用在oc上,纯swift是不支持runtime的,但是也可以弄,坑可能比较多,这就是我至今不考虑用swift的原因了,估计很多以前的大项目,也没那么快转到swift上开发,新语言看似很好,但是改变的成本总是很大的,swift在小项目当玩具玩一玩还是不错的,但是要有心理准备,坑,https://github.com/OnelongX/MyApp,但是这个没有用上cocoapods,我本地的测试的demo是用上了,其实都是差不多,就是网上很多人xib等UI文件,比较麻烦。不过Framework是支持xib文件打包的。
    既然说到xib和storyboard了,最近看了很多评价,还有自己项目的思考。发现xib和storyboard在多版本并发开发不方便,同步相当麻烦。xcode升级也会带来一些问题。所以在产品开发中,还是建议纯代码写吧。大型项目就不用说了,基本都是纯代码。如果追求开发效率,xib和storyboard无疑是最好的选择,但是迭代的时候就蓝瘦香菇了。
    cocoapods是非常有用的,希望大家不怕麻烦,下决心折腾一番,定会有收获的。 

  • 大并发服务

    post by onelong / 2016-10-14 5:31 Friday [工作]

    App----->DAL(队列+连接池)--->DB

    阅读全文>>

  • 怎么保证服务可靠性、数据一致性、以及一旦宕机数据恢复

    post by onelong / 2016-10-14 5:30 Friday [工作]

    服务可靠性的核心是:容灾,大灾难一般两种:节点故障、IDC故障。

    IDC故障,就是如果整个业务服务都在一个机房,整个机房如果down了,相当于整天个业务都完全无法服务了。

    阅读全文>>

  • 青山常在,细水长流

    post by onelong / 2016-10-8 14:44 Saturday [工作]

    自从接触了golang的协程之后,开始对协程有了浓厚的兴趣,tx的libco,通过hook的方式,将原来的同步io,转换成异步的协程io,在网络方面确实有很好的表现。对于协程这个东西其实很多开源库都用相关的实现,所以并不是什么很神奇的东西,如boost,libgo,当然也要说一说基于libgo的libgonet了,总的感觉呢,libco会比较简单实用些,不过只支持linux,libgo支持linux和win,boost是全平台支撑的,但是它是一个通用库,不怎么好用。关于协程的实现很简单,主要是用ucontext来保存切换上下文,但是简单提供几个协程函数,很难用,http://blog.csdn.net/qq910894904/article/details/41911175 ,golang的协程库好用是因为在语言级支持,如“go xx()” 自动会在异步协程里面执行,同时还提供了一套消息机制Chanel,group等完成同步和通信功能。自己实现协程的话,要实现这一套通信机制比较麻烦,但是如果没有这一套机制,还不如用线程。协程和语言无关,java同样是有协程库的,只不过不是官方支持而已。据说后来的jvm thread和系统的thread是一对一的关系,所以只要有支持cpu切换上下文的函数,其实就可以实现了,作为在语言榜一直排行第一的java,肯定用在底层有提供这类的api的,就算没有协程,还有actor的设计模式。说了那么多,其实你会发现在工作的过程中,很少要自己从新设计一个公共库的,用好开源库就好了。协程也好,线程也好,线程池也好,很多开源库已经很稳定了,不需要开发人员去折腾了,折腾了也没有非常大的意义,知道原理用好就算精通了。虽然很多人要较劲,一定要自己实现一套,这样才能体现自己实力,但是很多时候折腾到半死,结果发现有很多问题,还不如直接用开源的,哈哈哈。研究开源技术,只是为了让项目的可控性更强,并不是为了在必要的时候抄一套来展现自己。在很多的面试的时候,面试官喜欢问题,假如让你重新实现某个开源库,你的流程是怎样怎样的?一个小公司小项目,其实怎样做都,性能都不会很差,还要重写开源项目?所以有些装逼的面试官才会问一些很奇怪平时都用不到的东西,工作主要是解决问题的能力。
    工作之余,我还是喜欢了解一些开源技术,偶尔会选其中的项目,看看源码,了解其原理,例如之前的dubbo。另一方面给自己积累一点东西,万一将来遇到类似的项目,可以少走弯路,迅速上线。学习很多时候是为未来准备的,现在用的很多东西,其实都是两年前积累的,就算现在不学,面对当前的工作还是没啥压力的,但是人要向前看,不管未来怎样,至少不应该浪费时间,至少留下点什么。学技术本身就需要坚持的意志,技术之路往往是寂寞的,很多时候没人帮助你,甚至都没有和分享。人的成长之路,自己本身就是最大的敌人,克服内心各种借口,坚持下去本身就不容易了,更不要说不断的突破自己,每天像打鸡血一样。
    青山常在,细水长流,累了烦了就放空自己,回到原点,重新开始。 放松不是放弃,休息够了还要想办法拿起来继续往前走。

  • Linux线程和go协程

    post by onelong / 2016-9-22 21:59 Thursday [工作]
     记得我以前在简书上写过一个篇文章,多线程基础 今晚我想继续聊一聊这个坑,先聊一下最近的惨状吧,中秋前感冒了一次,吃了点感冒了好了,中秋后再来一个半死的感冒,全身疼痛,感觉是被人毒打了一顿,经过几天的悉心治疗,略见好转,想把今天所想的东西写下来。病号突然想去了解一下golang,想了想学习新的东西主要是了解它的特性,就是特有的功能,而不是简单复习一次语言的语法。golang里面最大的不同就是协程,golang里面没有线程这种东西的,可能是谷歌故意放弃了吧,后来细心想了一想,有协程就够了,已经不需要线程了。看了知乎的文章后,http://www.zhihu.com/question/20862617?sort=created 我更加坚信有协程就够了,不需要线程,协程是更小的执行粒子,作为一个java出身,自以为了解操作系统的人,肯定会去对比协程并发和当前多线程并发,于是就引出了一堆问题了。因为操作系统概念里面是没有协程这个东西的,所以语言上面的协程肯定在操作系统上得不到对应的映射。所以第一次猜想协程是依附在操作系统线程上执行的,因为线程是操作系统最小的执行单位。golang在语言级支持了协程,对开发者很友好。协程和线程的对应关系可以是一对一,多对一的,总而言之,尽可能的减少线程上下文(cpu context)的切换,极大提高cpu的利用率。在网络的开发中,我们会遇到很多io阻塞,系统调用阻塞等,这些操作可能会导致中断,切换线程上下文,这些都是不利于我们更有效的使用cpu的。golang很优雅的封装了一套协程api(事件驱动+channel),使得原本需要复杂代码实现东西,变得极其简单高效。事件驱动+channel是golang的灵魂,如果没有这两样东西,golang就什么都不是了,因为用户控制协程切换的途径就是channel等待。golang的协程并不能完全避免线程上下文的切换,在sys call的时候,还是要切换线程的,和操作系统的做法区别不大,到这里我对协程就聊到这里算了,想了解各种细节的人可以看看知乎的文章,尤其是那些图片,这是很有帮助的。下面我来说说另外的坑。

    工作5-6年了,时间算长了,看到一篇文章说golang的协程不是基于用户线程实现的,是库实现的,我就在想难道没用pthread?然后引发一堆狗血。其实我们会接触一堆概念:内核线程,内核进程,轻量级进程,普通进程(用户进程),用户线程等。 确实我很多年前就看过一些相关的文章,那时候看过之后自以为了解了,而今天发现确实想得太少了。对内核而已,是没有进程的,所以没有内核进程,只有内核线程。在Linux的书籍上都是这样说的,“linux线程是
    轻量级进程”,它是一个特殊的进程,没有共享内存而已。内核线程和轻量级进程是一对一的,也就是说对Linux而言,管理线程和管理进程是一样的。下面继续引用一段描述帮我们理清关系吧:
    我们知道,Linux的线程实现是在核外进行的,核内提供的是创建进程的接口do_fork()。内核提供了两个系统调用__clone()和 fork (),最终都用不同的参数调用do_fork()核内API。当然,要想实现线程,没有核心对多进程(其实是轻量级进程)共享数据段的支持是不行的,因 此,do_fork()提供了很多参数,包括CLONE_VM(共享内存空间)、CLONE_FS(共享文件系统信息)、CLONE_FILES(共享文 件描述符表)、CLONE_SIGHAND(共享信号句柄表)和CLONE_PID(共享进程ID,仅对核内进程,即0号进程有效)。当使用fork系统 调用时,内核调用do_fork()不使用任何共享属性,进程拥有独立的运行环境,而使用pthread_create()来创建线程时,则最终设置了所 有这些属性来调用__clone(),而这些参数又全部传给核内的do_fork(),从而创建的"进程"拥有共享的运行环境,只有栈是独立的,由 __clone()传入。 
    Linux线程在核内是以轻量级进程的形式存在的,拥有独立的进程表项,而所有的创建、同步、删除等操作都在核外 pthread库中进行。pthread库使用一个管理线程(__pthread_manager(),每个进程独立且唯一)来管理线程的创建和终止,为 线程分配线程ID,发送线程相关的信号(比如Cancel),而主线程(pthread_create())的调用者则通过管道将请求信息传给管理线程。” 
    从上面可以知道, 
    轻量级进程是用户态调用sys call创建的,而子线程是用master线程创建的,都是需要系统调用的,开销不小。线程池技术是为了减少频繁的创建销毁线程,提高cpu利用率而生的。所以golang协程执行在一个线程池上,至于这个线程池是不是基于pthread lib这个就不好说了,或者Google的牛人直接sys call 实现了,不使用用户线程,不管怎样,协程是新概念,但不是新技术,是另一种比较科学并发模型。最后留下一点点东西吧,https://github.com/cloudwu/coroutine c语言版本的协程,因为没有在语言级别上支持,比较难用,需要消息队列来配合使用,但是原理是相似的。 

  • 自定义网络协议

    post by onelong / 2016-8-31 20:48 Wednesday [工作]

    2012年的时候,来到深圳做局域网无线控制,最开始参考别人协议做的控制,别人用的是http,http是无状态的,一个请求完成会断开,下一个控制要重新连接,做实时控制比较麻烦。所以我们我用的socket长连接,在最初的时候,因为没人有经验,直接tcp,只管发送,不管发送是否成功,默认它是成功的,假如丢包了,tcp本身就有重发功能,也就是这样,在断网或切换网络的时候,客户端并不能马上检测出来是否断开了。于是加了心跳和超时,心跳也是单向发包的,需要服务器端确认,如果超时了就认为是断开了,则重连。经过一系列的修改,客户端通讯变得稳定了,但是还是有问题,控制数据包有时候也会丢掉,导致控制无反应。于是还是加了响应包,解决了问题。后来数据包多了,发现有些丢包是因为粘包了,后来继续定了一个规则进行把粘的数据包分开。最初的分包规则很简单,和http差不多用\r\n分开,也就是每个数据固定用\r\n结束。我最初接触到网络封装协议就是这么粗暴的,我知道很多人大学的时候都搞过了,我们当时的老大却没有给我任何建议,就这样弄成了一个产品,后来这个产品装机量也到达30w,还得了很多客户的好评。
    每次说到网络协议,我们总觉得这个东西特别高深的样子,因为概念有点抽象,一说到自定义协议,很多人就吓住了。其实协议有简单的也有复杂的,主要是看需求 ,上面我们定义的协议就非常简单了,如发送的消息包:touch\nx,y\r\n,x,y是两个参数。然后服务端收到这个消息包之后,发送一个回应包如:touch\nok\r\n。是不是很简单呢!这样也是一个协议。定义协议呢,主要要处理好两样东西:1、粘包,2、响应。任何一个请求消息都应该有一个响应包,告诉对方“你发送的东西,我收到了”,这是最基本的。在处理通讯的时候,由于各种网络环境的原因,数据包粘包是必然存在的,所以定义的协议的时候,应该给出分包的解决方案。当前自定义协议比较常见分包方案有两个:1、如上面,用行分隔,这样做法常用于文本类的协议。 2、长度分包,例如一个消息包含两部分header+body,header里面第一个字段是整个消息的长度,header可能还包含如消息类型,版本等字段,具体情况按需求定。body是就是消息的主体,消息主体可以放各种对象,String,json,protobuf等。说到这里,我想你对自定义网络协议感到很无语了,这么简单么?的确基础的东西就是这么简单。
         我在2013年写过嵌入式的java服务器,当时是给ipad上传文件的,还有给电视盒上传文件。从http到webdav走了一遍,以前在东莞的时候做过邮件相关的软件,熟悉了smtp,pop3,imap等,协议定义确实是不太复杂,协议复杂的原因,很多时候是因为复杂的业务需求。好了下面简单看一看xmpp的协议的几个应答,其实大部分协议都差不多,只是格式不同而已。
    获取联系人列表请求内容如下:

    阅读全文>>

  • 满满的收获

    post by onelong / 2016-8-19 21:09 Friday [android]

    好久没有做Android的项目了,一直刻意去回避,都在折腾iOS的项目,好多人问是不是转型了,其实也不是吧,只是觉得iOS会纯粹一点,再加上以前在iOS上的实践太少了,没有足以让我无比自信的去面对所有面试。最近因为特殊情况,让我回到刚毕业的时候,熬了4个晚上优化一个项目,给自己交上满意的答卷。这4个晚上,用了洪荒之力,鬼知道我经历了什么呢。。。。。哈哈,没那么夸张。其实看着师弟惆怅了一个月,种种跌宕起伏,之前给他做这项目的哥们,用了洪荒之力都跪了,一方面看着那个app做的太丑了,另一方面出于好奇,同时想证实自己给那个哥们的建议,于是自己找苦来吃了。结果呢,好屌。。。。。
    这次优化都用了哪些技术和工具呢?首先是应该有一个好的思维,我打个不太恰当的比喻吧,你拿到一块地,地上有一堆牛粪,那个哥们呢,喜欢在牛粪上差点鲜花,鲜花的华丽虽然掩盖了牛粪,但是终究是不够优雅。而我就想着先清理那堆牛粪,然后再种上鲜花。所以第一步,我做了代码清理,把一些重复,多余的框架去掉,一个项目3个图片加载框架,2个网络请求框架,费不费劲呀?一样一个就够了。那哥们说Facebook的fresco很好,不要用Universal-Image-Loader,按照他的意思是因为Universal-Image-Loader性能不好,导致app频繁崩溃了,好明显是没有找到原因,胡乱搬库,以往用好了就说是自己的经验了,的确android开发者很多就处于这种水平。这个问题恰恰反映这个问题。
    我解决问题的过程是怎样的呢?首先询问师弟运营的数据,例如android用户在集中在那个版本上,毫不意外,基本没有android2.3的用户了,都是android4以上了。这样意味着不需要兼容android2.3了,也就是直接可以app的largeheep,打开了之后,崩溃已经明显少了,但是用了10-20分钟,还是出现内存溢出。经过计算10-15张560x560的图片,内存最多才20m,而app监控到了180m内存,很显然内存泄漏了。于是我自己手动管理图片的内存,但是依然无效。android内存泄漏一直以来都是开发的难点,面试经常有人问的。之前用过MAT,完全看不懂,后来试了一下facebook的LeakCanary,果然好用了,的的确确发现一堆堆内存泄漏,一泄漏就是10多m,妈的。。。。。得益于这个工具,很快就找到问题了,大部分是因为没有正确使用hander,线程导致的,activity退出应该清理没用的数据,移除没用的消息。经过一番折腾,内存明显可控了,峰值最多120m,我看了支付宝有时候内存占用都180m,所以我断定可以了。结果发给师弟它们测试,玩了20分钟,没啥问题,这是算完了?不是的,这么多图片好卡,于是我适当做了延时加载和缓存,真个界面就流畅起来了。
    想着既然做了,那就一优到底吧,把里面支付的,图片加载的,网络的库都升级到最新的,这样更好兼容android6.0吧,网络还是用我比较熟悉的volley+okhttp,不过这次用了okhttp3,之前在案场用了okhttp2.0。换库发现
    volley本身有内存泄漏,也是这样我发现了好神奇的东西,java无用的对象尽可能置为null,加速gc。发现列表滚得卡顿,于是再优化了一下,列表滑动时不加载图片,果然流畅了,这次的优化也结束了。
    为什么用volley,没有用retrofit呢,原因1:这个项目从android-async-http切换到retrofit比较麻烦,可能是我不熟的原因吧,原因2:volley代码少,我很容易做到有问题快速库,一切都在掌握之中。对于recyclerview,还没开始用,我觉得复杂的列表界面应该切换到recyclerview,在recyclerview我看到很多优点,很灵活。LeakCanary是个神器,建议大家用。
    送上几个截屏吧,二手iPhone,找靓机。哈哈,开发用二手机不错哇。。。

    阅读全文>>

  • IM的学习历程

    post by onelong / 2016-8-11 16:59 Thursday [工作]

    最近闲下来想起在虚拟机上部署一年前部署过的企业级的即时通讯方案-TeamTalk,很辛苦的折腾了两天终于部署成功了,一年前糊里糊涂的部署在阿里云上,一年后阿里云过期了,不想续费了。这次部署和上次部署不同的地方在哪里呢,我已经不需要官方提供的文档了,自己构建服务器编译环境,在ubuntu 16.04,内核4.4.0,gcc 5.4上编译通过,还升级了php7.0。说这些有什么用呢,其实我就想说的是时间是最好的催化剂,无意间见证了成长。很多时候很迷惘,学这些东西,学那些东西有什么用呢,短期内能见效很快的就是考试了,大学里面考试前一晚努力点,哪怕你一个学期没上课,都可以考试及格。知识积累过程,量变到质变的过程通常是漫长的,折磨人的。炒股里面经验有人说,投资是一场修行。学习也是一样,没有达到一定基础积累,短期是没有明显的效果的。在开始学习TeamTalk之前,我曾经研究过在一份java即时通讯的代码,当时看那个代码一头雾水,当时听说它能支撑100w用户在线,我觉得很有意思,因为不曾有这样的机会去见识一下。经过一段时间的学习,分拆,最后我折腾了一份只有IM的代码,去掉了分布式消息路由,去掉了分布式存储和mongodb,用HashMap代替了,还用netty4重新写了一部分,源码地址:https://git.oschina.net/onelong/IMBase.git 后来在某种情况下得知了TeamTalk,折腾了1个星期,也将TT部署到阿里云上了。那时候很有心想做个自己的IM,却无力去研究那些c++代码,后来将基础代码弄到Xcode上面运行,开始熟悉了部分流程了,但是后来还是觉得太吃力了,不会改c++,也不懂它是怎样的协议。对于Google protobuffer 也不熟悉,源码地址:https://git.oschina.net/onelong/TTBase.git,后来去深圳带项目了,也就放下了。在去深圳之前,我自己封装了一个整合了一个android的网络库,也就是现在项目用的网络库,volley+okhttp还有图片加载的,https://git.oschina.net/onelong/Mylibs.git 本地还有部分修改,没做同步。项目差不多做完的时候,公司说要自己做android的推送,我又开始研究DDpush,大约花了2个星期吧,又熟悉了整个推送的协议,优缺点等,https://github.com/OnelongX/DDPush.git,并成功弄了一个demo,在做demo的过程还研究了别人的流氓常驻方案,不过那些方案在android5或者android6上都失效了,这次快速熟悉还是得益于之前对即时通讯的研究。由于项目推进不达预期,目前推送方案还没有正式在线上使用。之后的一段时间在折腾c++11和linux网络,在强大的clion和cmake帮助下,研究了一个简单基础开源网络库handy,https://github.com/OnelongX/handy.git 大约一个月的时间吧,基本熟悉了Linux高性能网络的要点,异步+事件驱动+多线程,也是这样渐渐的理解nginx的配置参数了。经历了这些,做完看TT服务器的基础代码,发现如此的简单,没有以前觉得用c++特别神奇的感觉。各个流程基本都是可以猜出来,例如怎样解析协议的,TT的协议是16B头+protobuffer序列化的body,通过长度协议分包。既然提到了Google protobuffer,我有必要说一说这个神奇的序列化工具,当代游戏通讯,IM,RPC等都大量使用了它,有兴趣的可以自行了解,我相信你会有一番收获的。
    学习在与坚持,发现了一个有兴趣的事物,迅速的学习它并掌握它,而不是等或者看过了就算了。很在东西在深挖细节之后才会自己的不足,学得越多,越会发现自己的更多不足。学然后知困。学会争取机会锻炼,而不是一副事不关己的样子,错过每一个成长的机会。很多时候,别人写的代码没有问题,自己抄着写都会有问题,为什么呢?因为不知道细节和本质,有经验的人在写的时候就避免了。

  • 网络处理经验

    post by onelong / 2016-8-7 15:32 Sunday [工作]

    最近在升级网络库,从AFN 2.6.3升级到AFN 3.1,发现了导致了很多问题,之前在2.6.3很多显示使用了GCD处理的,升级之后出现了问题,导致下拉控件死锁无法收回。在各自的控件内,好难调试找出问题,很多时候靠经验推测。从SDWebImage 3.7.6 到3.8.1,同样导致一些以前可以显示地方现在不能显示了,3.8开始使用了URLSession,放弃了之前的NSOperation+urlconnection,之前很多可以通知更新UI的地方,现在出现了效率很低的问题。尽管在UITableView上面没什么问题,原因是UITableView是自动刷新界面的,而不是通知的。对于UITableView还在努力使用懒加载,尽可能在滑动的时候不加载UI,停下来的时候加载可见空间的UI,理论上这个是最高效率的,可以减少没有必要的请求,尽管系统控制了网络请求的并发,但是多余的请求在等待队列里面肯定会增大等待时间的,这个做法在网上可以找到参考方案。现在GCD用得很频繁,但是也不要过分使用,尤其在不够清楚原理的时候,一旦出现随机问题,调试会相当痛苦。URLSession默认情况响应都是在主线程调用,然后你又在它的回调里面搞个同步的东东,马上挂了。
    AFN默认maxConcurrentOperationCount是1,也就是单个队列的并发是1,在iOS的网络配置里面还有一个参数可以配置的,HTTPMaximumConnectionsPerHost,默认是4。我的理解是4个client客户端的意思,全局理解呢,就是手机进程默认启动4个http client,每个http client都自己并发队列,默认是串行(先进先出)的。我在案场的项目无意配置了HTTPMaximumConnectionsPerHost=1,默认maxConcurrentOperationCount=1,在多请求的界面上比android慢了很多,也是经历这次,我才意识到之前对参数不理解。优化后HTTPMaximumConnectionsPerHost=4,maxConcurrentOperationCount=4,客户再也没有说慢的问题了。同样的配置,在另外的项目出现了很奇怪的问题,例如下拉无法收回。虽然我没有修改配置测试,只是注释掉那些GCD的代码就没有问题了,我在猜想如果将maxConcurrentOperationCount配置为默认值就应该没有问题了,下次闲着的时候再试一试吧。
    以同样的原理,在案场项目里面做了退出界面,关闭无用的网络连接也是一种优化网络的手段。
    说完网络, 我说说别的吧,这周做了个在Tableview cell支持多行输入的东西,这个东西让我了解到Tableview不一样的地方,使用beginUpdate,endUpdate可以不reload cell刷新行高,效率非常明显。无论是使用Autolayout还是绝对坐标,只有你明白其中奥秘,都可以顺利的实现想要的效果。
    折腾了那么多,我觉得现在是有必要认真的阅读一些开源库的代码了,例如AFN,SDWebImage,虽然我之前看过好几个网络和缓存的开源项目,但是没有在项目里面经过高强度的测试,感触还是比较少的,都是基于理论的理解,而并非在经验层面上理解。朋友说他们的项目有5w多用户,我觉得这点上还是蛮有意思的。曾经有点冲动想去优化那个20多w用户的android app,后来想想,要是这个在过年放假的时候,我估计还是会弄下来的。我一直喜欢做点有挑战的事情,在工作中看到不好的,我都会想办法优化掉,虽然过程比较累,比较折腾,甚至熬夜,但是我觉得一切都是值得的。一个人的经验,靠听说的,靠看到的,肯定不够靠谱,自己亲身经历的才是实实在在的自信和实力。工作也好,生活也罢,努力去让自己问心无愧,努力让我自己觉得不是在浪费生命,而是在进步。一个人,无论在百度,还是腾讯,甚至在创业公司,你想得更多,都得靠着自己付出,指望不了别人引导你,帮助你。在BAT工作的人,本身工作量就大,谁也没有时间去管你,就是有时间,有时候也不好意思叫你学这个,学那个,毕竟每个人都有自己的私人空间和发展方向。
    成长和机会都靠自己争取的。

  • 找靓机二手手机app产品迭代

    post by onelong / 2016-8-5 19:39 Friday [工作]

    先上2.1版本的几个截图吧

    点击查看原图点击查看原图点击查看原图

    阅读全文>>