iOS 开发小记 (六)

这一篇是最近开发遇到的问题:

一,善用Category 实现功能分块与重用

UIViewController+UIImagePickController,实现了选择照片的功能。

一个APP中选择照片的地方有很多,用category实现后,使用时每个地方就只需一行代码。

至于选中后的回调,考虑了Block、delegate、notify,最终还是选择了notify。

原因是category存属性的问题,不知道objc_setAssociatedObject 放进去block和delegate之后,ARC会发生怎样的变化。

把选中的图片,用objc_setAssociatedObject存储,再发出notify,完成catgory实现的选择照片功能。

2,图片浏览功能

APP中需要浏览大图的地方很多,网上也有很多开源的第三方图片浏览器,在网上看了下,很多功能用不到,于是决定自己弄一个。

功能:查看大图、放大缩小、有删除返回功能。

最后实现的方案:

新建一个controller,view上放置一个scrollview,scrollview上放置UIImageView。controller通过push 的形式调用,这个调用同样用category封装起来。

几个精妙的地方:

UIImageView放在scrollView里面后,要设置宽度、高度大于等于view(controller的view),图片显示是center;这样的好处是,当显示一个图片的时候,默认是放在view正中间,而且是图片的原大小。

通过scrollview的zoom来实现放大缩小,直接在IB里面填入最大最小的倍数,就可以实现放大缩小。

回调功能,删除的时候通过block回调删除方法。这里一开始采用的是notify,后来发现notify 的时候需要传参数,而且很多地方需要的参数都不一样,如果一一通过notify设置,会很复杂,于是改用block。

三,OC的继承关系

假设有类Parent,其中有方法methodA,里面有调用[self methodB];

有类Child继承Parent,同时也重写methodA,methodB。

这时候,就会出现问题:当Child调用methodA的时候,[super methodA]里面的[self methodB],调用的是Child的methodB。如果Child在methodA里面也调用了methodB,那么就会出现子methodB调用了两次,而parent的methodB没有调用到。

实际开发的场景中,Parent是BaseViewController,Child是childViewController,methodA是viewdidload,methodB是customView。

当child再viewdidload的函数中调用[super viewDidLoad] 和 [self customView]的时候,就会发生child的customView调用了两次,而parent的customView一次都没有调用到。

解决方案:1,不要用一样的名字,child的改成customChildView;

2,在child的customView中调用, [super customView]。同时child不要调用customView。

(这个也是self和this指针的不同,如果是c++的话,在[super viewdidLoad]的函数中,调用的 customView应该是parent的customView。

四,MVVM架构中的model与viewModel

viewModel的生命周期随着controller,而model一般是整个app的生命周期。

个人的开发习惯是,把model当成一个持久化数据库。network请求写在viewModel中,请求成功数据后,把数据update给model存起来。

如果是遇到有很多viewModel 需要做同一个请求的,把请求放在model,而model直接向model请求。

谈到网络请求,不得不说异步回调的问题。

APP通过网络加载数据,必然伴随着加载完毕的回调。

解决方案:

1,RACObserve Viewmodel中的属性或者model的属性(不太建议对model中使用RACObserve)

2,把请求封装在RACSignal里面,通过subscribeNext或者subscribeCompleted来进行回调。

个人是两个一起用,1用来观察常变的值,通常是绑定一个viewModel和View时使用;

2常用于用户操作后进行网络请求,回调后进行刷新,通常是reloadData的形式。

五,Websocket的实用

开发中遇到一个功能,需要用到服务器向客户端发送消息和保持长连接,同时又是一个http服务器,于是用到了websocket。

地址是ws: 或者 wss:开头,wss需要证书,这次用的是ws:。

用的是开源的SocketRocket,非常简单。使用时通过open连接服务器,如果失败,有fail。连接后收到消息有didRecive,断开连接有close。

这个地方使用一个静态的viewModel来存储webSocket,保证app生命周期不会重复创建。把服务器返回来的status放置到viewModel,controller通过RACObserve来观察这些status。很完美实现了这个功能。

六,删除功能与刷新功能

一个APP框架要和需求、功能相适应,这样当产品提出一个合适的需求的时候,不至于手忙脚乱。

最近做的这个APP,有一个功能是删除一个动态,这个动态在很多列表都会出现。这里可以采用监听者模式,删除的controller通过notify发出事件,而需要更新的controller自己监听这个事件,从而更新视图。

同时,这个在列表中用左滑删除的功能(用户侧滑删除 -- 后台请求服务器删除 -- 删除返回 -- 内部删除数据 -- UI动态显示删除)  用ReactiveCocoa来实现非常方便。

七,修改Pods第三方的代码

功能需要修改第三方的代码,这个问题比较麻烦。

1,通过podfile 把pods的路径加一个 => "github...." 定位到自己的github。

2,工程导入形式, pod "../../test"   直接修改工程文件。

3,复制代码到工程,直接修改。

用的是第二种方法,一开始尝试直接在pods里面添加文件失败。在导入的工程修改完后,再运行一个pods Install。发现.xib没有导进来,应该是自己对pods的理解还不够深。

八,测试

单元测试:对本地一些自定义方法进行测试。

UI测试:可以点录制,点击模拟器,然后生成UI测试代码(几乎不可用)。

异步测试:

1,自己实现。用runMode等待,轮询判断是否完成。

2,execption。自带的异步测试功能。

九,图片压缩

从系统中选择照片后,图片都很大。压缩成宽高 不超过一定数目。

UIGraphicsBeginImageContext 和 UIGraphicsGetImageFromCurrentImageContext , 配合UIImageJPEGRepresentation解决了问题。

图片压缩:前面两个函数是缩,后面一个函数是压。

 

十,视图跳转

APP中经常有页面的跳转,遇到一个需求是在TabA的页面中,需要跳到TabB的页面,同时要push一个新的页面。

一开的时候经常遇到log打出来的warning。思考了一下,发现是自己的操作太连贯了。

当跳转TabB的时候,rootController还没显示,就开始push新的页面。

解决方案:延迟0.1s进行push操作。

(最后还有一个warning,是关于UISearchController的,在stackoverflow找到答案:在dealloc中把searchController的view removeFromeSuperView。)

 

 

这次就先写十点吧,下次接着写,还有关于推送、IM聊天、地图、自动布局、发布测试等等。

原文地址:https://www.cnblogs.com/loying/p/5113273.html