ios组件化三种方案
前言:
前段时间由于公司业务的需要,要求对项目进行组件化的拆分,减少各个模块之间耦合。希望达到的效果是各个组件能单独的打私有pod,方便在其它工程里引用。由于项目现在比较庞大,目前只做了本地拆分。期间学习了很多有关组件化方面的知识,现在做个总结,后面会有有三种方案相关的资料链接。先上我自己对于三种方案总结的一个demo,github地址
概述:
组件化是为了各个模块不进行直接的相互引用,降低耦合度,那么如果组件A想调用组件B的时候要怎么办呢,其实原理上都是通过中间件来调用,而不需要模块间相互引用。 我们所看到的组件化方案,大体总结来说有三种:
- 1.procotol方案
- 2.URL路由方案
- 3.target-action方案
一、procotol协议注册方案
关于procotol协议注册方案见到别人分享比较少,有次查资料的时候看到了,就研究了一下。
在demo中ProcotolManager作为中间件:
1 | - (void)registServiceProvide:(id)provide forProcotol:(Protocol *)procotol; |
所有组件对外提供的procotol和组件提供的服务由中间件统一管理,每个组件提供的procotol和服务是一一对应的。
在ProductDetailServiceProvide中:load方法会应用启动的时候调用,就会在ProcotolManager进行注册。ProductDetailServiceProvide遵守了ProductDetailServiceProcotol协议,所以对能外提供productDetailViewControllerWithProductId服务。
1 | + (void)load |
所以在首页中,通过ProcotolManager取出ProductDetailServiceProcotol对应的服务提供者ProductDetailServiceProvide,就可以调用产品详情中所提供的服务,而不需要进行直接引用。
二、URL路由方案
URL路由方案参考的是蘑菇街MGJRouter方案
蘑菇街 App 的组件化之路,讲的比较详细。
三、target-action方案
target-action方案是在学习CTMediator的基础上进行的,ZCMediator作为中间件,里面的实现也比较简单。
1 | - (id)performTargetName:(NSString *)targetName actionName:(NSString *)actionName paramters:(NSDictionary *)paramtersDict; |
执行时查找对应的target有没有对外暴露的服务,如果有则执行。
主要的还是每一个组件暴露出的category,是对中间件的一个扩展,调用每个组件对应的category方法,然后在通过中间件调用对外暴露的服务。
1 | #import "ZCMediator+ProductDetail.h" |
我们项目里使用的就是target-action方案。下次再写一篇几种方案的比较吧。
参考链接:
MVVM使用
1.最近比较忙,一直在忙着新项目的开发。以前的项目都是用mvc模式,有些复杂的页面的controller代码里会比较多,虽然也做过一些拆分,但是还不能满足老大的要求。所以在新项目中使用了MVVM模式,MVVM模式的介绍网上的文章一搜一大堆,我这就不介绍了。
2.看过MVVM的一些文章,肯定会知道RAC,虽然说MVVM模式和RAC并没有什么关联,但是RAC对于MVVM模式中ViewModel和View的绑定,ViewModel和Controller的绑定来说相当方便。
3.值得一提的是,我们加入了一些自己的创新,我们给Controller都新增了一个RootView,加在Controller的View上,所有的视图层展示和操作都在这个RootView上进行,这样Controller里面的代码就非常少了。刚开始我们项目中的哥们提出这个方案时,我们一度很不能理解为什么要这样做,这样不是多此一举吗,毕竟每个Controller都有自己的View视图,而且视图中的一些操作我们就不能直接告诉Controller了,还有就是ViewModel处理的一些数据我们要怎么样既能告诉Controller又能告诉RootView。后来经过大家的讨论,觉得这个方法还是可行的,并对上面的疑问都提供了方案。
3.1 对于RootView中的一些操作不能直接告诉Controller的疑问,解决的办法有很多,通过Block回调,代理,RAC都能解决,虽然多做了一步,但还是很方便的嘛。
3.2 对于ViewModel处理的一些数据我们要怎么样既能告诉Controller又能告诉RootView,我们的解决办法是Controller和RootView公用一个ViewModel,这样你想和谁绑定都行了。
3.3 现在我们都认为单独抽出一个RootView是个很不错的决定,无论用哪种设计模式,最后无非都是为了给Controller减负,减少Controller里面的代码量,使结构更清晰。其实想想每个工程里都有一个Window,Window就相当于幕布,所有的Controller的表演都在幕布上进行。那现在把Controller的view想象成幕布,你所有其他View层的表演都自己进行,最后在我的view里面统一放映进行了,管理者少了不少工作,立马就轻松了.
4.最后上代码吧,很简单的一个demo,希望能对大家有所帮助。github地址
基于PhotoKit写的图片,视频选择器
1.在公司的项目中,图片选择的时候需要自己定义一个图片选择器,自己根据PhotoKit写了一个Demo,也顺便学习了一下PhotoKit,自己扩展了一下,既能选择图片也能选择视频。
1.1 图片选择,如下图:
1.2 获取相册,如下图:
1.3 视频选择,如下图:
2.相册和媒体的获取代码主要在ZCPhotoManager这个类里面,接下来可能写一篇关于PhotoKit介绍的博客。
2.1 获取相册
1 | - (NSMutableArray *)showAlbums { |
2.2 获取相册中的媒体
1 | - (PHFetchResult *)assetsInAssetCollection:(PHAssetCollection *)album{ |
2.3 然后主要的功能就是图片的展示,布局。
3.直接上Demo
3.1 由于时间比较短,里面的UI写的可能有点粗糙,主要是为了自己学习,就这样吧。
MBProgressHUD的一些常用的封装
1 项目中,大部分的网络加载时都会加上一个等待菊花框,MBProgressHUD是一个很好用的第三方库,在MBProgressHUD基础上进行了一些封装,在项目中用到的机会比较大,希望对你们有用。
1.1 第一种就是就是普通的菊花,如下图:

1.2 提示Toast,网络请求提示,报错,提醒之类的,如下图:

1.3 gif图类型的菊花,现在大部分都不用系统的菊花了,都会用gif图代替,如下图:(图好像截的有问题,具体效果看代码)

2.下面上代码:
3.提示一下,有时候一个控制器可能同时进行多个网络请求,需要多个请求结束后再隐藏菊花,里面也提供了方法,使用- (void)hiddenWaitingForTransaction方法,里面也有例子,对于gif型菊花和普通型菊花都适用。
iOS明文密文切换时问题
1.项目中经常遇到密码需要明文,密文切换的样式,如下图:

2.切换过程中,会在10以下的系统会出现几个问题,1.出现空格,光标位置错乱,2.字体变化,3.密文时输入文字清空,下面分别列举出解决办法:
3.1 第一种问题解决办法,先保存文本,再清空输入,再赋值,就解决了空格问题
1 |
|
3.2 字体变化问题,重新设置一下字体,保持和现在设置的一样
1 |
|
3.3 密文输入清空问题,在代理里面,加多一个判断能避免密文清空的问题,如下:
1 |
|
iOS卡片式布局view
1.新版本的项目中,深深的感受到了设计对我们的恶意,设计的页面有这样的,

这样的

还有这样的

什么鬼,并不是几个页面只是这样的,而是大面积的页面都是这样的,当我看到时我的内心是奔溃的,但没办法,架不住设计师的坚持。
2.没办法,只有自己做了,刚开始分析下看能不能用背景图片来解决,后来发现自己想多了,因为根本没有规律,凹槽的地方根本没规律,都是出现在随心所欲的出现在各个地方。经过大家最后的商量,画出凹槽,往上面一块块拼接吧。结合Masonry,下面上代码。
3.例子里凹槽部分完全是自己画的,虚线和两个半圆。如果一屏展示不下你想要展示的view,可以用scrollview,再根据Masonry来控制scrollview的滚动范围,后面我会再传一下这部分代码。我一直在想能不能有什么好的办法可以解决,也希望有大神给我好的建议。
navigation黑边问题
今天在做项目时,出现了navigationbar 隐藏/显示 出现黑边问题,搞了好久,终于找到解决办法。。。
1.在网上找了好久,基本上都是以下的方法,如下:
1.1 在页面即将出现时隐藏navgaionbar
1 | - (void)viewWillAppear:(BOOL)animated |
1.2 在页面即将消失时显示navgaionbar
1 | - (void)viewWillDisappear:(BOOL)animated |
结果悲剧的发现黑边情况还是会出现,因为上述方法是针对页面间push时有作用,但是项目中我的页面是present一个登录页,坑啊,还好找到了如下方法,使用navigationController的代理方法:
2.1 页面即将出现时设置代理
1 | -(void)viewWillAppear:(BOOL)animated |
2.2 页面消失时取消代理
1 | - (void)viewDidDisappear:(BOOL)animated |
代理方法
1 | - (void)navigationController:(UINavigationController*)navigationController willShowViewController:(UIViewController*)viewController animated:(BOOL)animated |
TTTAttributedLabel 高度计算
1.TTTAttributedLabel里的文字高度计算和普通label的动态高度不同,如果你用普通label的动态高度计算的话,在TTTAttributedLabel里则显示不对
2.下面方法
1 | // tttLabel是TTTAttributedLabel的实例 |
ios画虚线
项目中用到了自己画的虚线,记录一下:
1 | - (instancetype)initWithFrame:(CGRect)frame |