
都说“三岁看老”,我在和谐社会中摸爬 打滚了也近三个年头,这不快过年了,今年朋友/发小寻找“心理平衡”的首选对象依旧是哥,看着大家满意而归的身影,荣幸之至!捧一捧凉水扑到脸上,抬头照照镜子打量着依旧“枯瘦如柴”的自己,看着时间给刻下的“抬头纹”,盯着那浑浊但依旧坚定的眼睛,哥想对自己说:“大雁,你可以的,虽然没有以前好配合了,你终有一天会成功的,虽然还很遥远!乖乖,好了,傻B可以写帖子了......”
前言
不管开发任何软件,我们的原则就是尽量做到“高内聚低耦合”。所谓“低耦合”是指软件结构中模块与模块之间的耦合度或关联程度,模块之间接口的调用及实现的复杂度、交互数据的多少等,决定了软件耦合度的高低强弱;所谓“高内聚”是从模块内部功能的层面而言的,模块内部特定功能的代码元素的紧密程度决定了代码内聚性的高低。
网上不乏有所谓“十分钟搭建强壮APP框架”、“快速搭建强壮APP框架”等帖子,且不去讲好坏,总之,实践是检验真理的唯一标准,今天我简单汇报下本人做项目时,框架的搭建流程及注意事项。
框架搭建
框架搭建是个劳神费心的事情,因为在搭建时你要考虑到各种可能,比如:怎么设计使得流程更清晰?怎么设计更易于分工协作?怎么设计更容易快速定位代码模块?怎么保证系统的易扩展性?等等都是我们要提前把握好的。先看下大致效果图如下:


一、 框架结构
APP的结构一般分为三条线:
- 一条主框架流程;
- 一条是用户登录框架流程;
- 一条其他如广告页、欢迎页等
相对而言,主框架流程较为复杂,顶级容器为UITabBarController,子容器为UINavigationController,其中顶级容器放3-5个导航控制器,导航控制器的rootViewController为各模块的首页。登录框架流程及其他一般为线性流程,个别会涉及到根视图的切换,相对简单,如果画成树状结构图的话大致如下:

二、 StoryBoard分离
为了配置三方库方便,我使用CocoaPods工程(基于CocoaPods 1.1.1),下为Podfile文件引入的三方库:
platform :ios,’8.0’
target ‘EVNEstorePlatform’ do
pod 'MBProgressHUD', '~> 1.0.0'
pod 'FMDB'
pod 'SDWebImage', '~> 3.8'
pod 'IQKeyboardManager', '~> 3.3.7'
pod 'MJRefresh'
pod 'MJExtension'
pod 'MWPhotoBrowser'
pod 'AFNetworking', '~> 3.0'
end
如遇到问题,可参照CocoaPods工作原理及使用中遇到的问题,解决或问阿度。
在实际的项目开发中,没有说谁的框架更优,结构都是大同小异,适合自己的团队才是最重要的。单从框架搭建及界面布局而言,有的团队喜欢StoryBoard,因为所见即所得,给外行介绍起来较为方便,一个模块的所有的界面铺满屏幕,很酷炫的感觉。有的团队喜欢纯代码,当看到自己写一串串字符渲染出“神秘”动画,说不出的满足感。当然我们团队奉行的是中庸之道,框架搭建+个别简易界面我们使用StoryBoard,其他使用纯代码的方式,这也是踩过坑之后,倒逼的结果。

毋庸置疑StoryBoard有很多的优点,但对于团队协作开发,有时会有说不出的痛,比如:同时修改StoryBoard文件遇到的冲突;即便是细微的位移调整,编译起来也需要足够耐心;更新了下Xcode怎么布局全乱了等等问题,正因为此,我们采用折中方案,尽量将StoryBoard分离使用,Main.storyboard中为主框架顶级容器和登录流程的顶级容器,而其他3-5个模块如,首页Host.storyboard、个人中心MineCenter.storyboard等,使用单独的StoryBoard文件,除此之外基本使用纯代码方式编写。



在进行故事版分离时,主要是自定义UITabBarController的过程。
首先,根据上面模板图,新建故事版文件;
然后,按照第一节框架结构图,将特定的控制器容器、导航控制器、视图控制器拖入对应的故事版中(StoryBoard文件);
再次,在自定义的UITabBarController中,连接各个模块,在这个过程中UITabBarController起到了应用的连接中枢的作用,为了炫技,哥做了个中间凸起效果,主要的TabBarController代码如下:
#pragma mark: 首页storyboard
UIImage *hostSelectImg = [UIImage imageNamed:@"hostViewSelect"];
UIImage *hostUnSelectImg = [UIImage imageNamed:@"hostViewUnSelect"];
UIStoryboard *hostSB = [UIStoryboard storyboardWithName:@"Host" bundle:nil];
UINavigationController *hostNaviVC = [hostSB instantiateViewControllerWithIdentifier:@"hostNavigationC"];
hostNaviVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"首页" image:[self scaleImage:hostUnSelectImg] selectedImage:[self scaleImage:hostSelectImg]];
hostNaviVC.tabBarItem.tag = 0;
#pragma mark: 关注storyboard
UIImage *attentionSelectImg = [UIImage imageNamed:@"attentionSelect.png"];
UIImage *attentionUnSelectImg = [UIImage imageNamed:@"attentionUnSelect.png"];
UIStoryboard *attentionSB = [UIStoryboard storyboardWithName:@"Attention" bundle:nil];
UINavigationController *attentionNaviVC = [attentionSB instantiateViewControllerWithIdentifier:@"attentionNavigationC"];
attentionNaviVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"关注" image:[self scaleImage:attentionUnSelectImg] selectedImage:[self scaleImage:attentionSelectImg]];
attentionNaviVC.tabBarItem.tag = 1;
#pragma mark: 发现storyboard
UIImage *findSelectImg = [UIImage imageNamed:@"findSelect.png"];
UIImage *findUnSelectImImg = [UIImage imageNamed:@"findUnSelect.png"];
UIStoryboard *findSB = [UIStoryboard storyboardWithName:@"Find" bundle:nil];
UINavigationController *findNaviVC = [findSB instantiateViewControllerWithIdentifier:@"findNavigationC"];
findNaviVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"发现" image:[UIImage imageWithCGImage:findUnSelectImImg.CGImage scale:1.5 orientation:findUnSelectImImg.imageOrientation] selectedImage:[UIImage imageWithCGImage:findSelectImg.CGImage scale:1.5 orientation:findSelectImg.imageOrientation]];
[findNaviVC.tabBarItem setImageInsets:UIEdgeInsetsMake(-14, 0, 14, 0)];
findNaviVC.tabBarItem.tag = 2;
findNaviVC.tabBarItem.selectedImage = [[UIImage imageNamed:@"findSelect.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
findNaviVC.tabBarItem.image = [[UIImage imageNamed:@"findUnSelect.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
#pragma mark: 购物车storyboard
UIImage *goodsCarSelectImg = [UIImage imageNamed:@"goodsCarSelect.png"];
UIImage *goodsCarUnSelectImg = [UIImage imageNamed:@"goodsCarUnSelect.png"];
UIStoryboard *goodsCarSB = [UIStoryboard storyboardWithName:@"GoodsCar" bundle:nil];
UINavigationController *goodsCarNaviVC = [goodsCarSB instantiateViewControllerWithIdentifier:@"goodsCarNavigationC"];
goodsCarNaviVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"购物车" image:[self scaleImage:goodsCarUnSelectImg] selectedImage:[self scaleImage:goodsCarSelectImg]];
goodsCarNaviVC.tabBarItem.tag = 3;
#pragma mark: 个人中心storyboard
UIImage *mineCenterSelectImg = [UIImage imageNamed:@"mineCenterSelect.png"];
UIImage *mineCenterUnSelectImg = [UIImage imageNamed:@"mineCenterUnSelect.png"];
UIStoryboard *mineCenterSB = [UIStoryboard storyboardWithName:@"MineCenter" bundle:nil];
UINavigationController *mineCenterNaviVC = [mineCenterSB instantiateViewControllerWithIdentifier:@"mineCenterNavigationC"];
mineCenterNaviVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"我" image:[self scaleImage:mineCenterUnSelectImg] selectedImage:[self scaleImage:mineCenterSelectImg]];
mineCenterNaviVC.tabBarItem.tag = 4;
#pragma mark: 连接
self.viewControllers = @[hostNaviVC, attentionNaviVC, findNaviVC, goodsCarNaviVC, mineCenterNaviVC];
最后, 创建各模块对应的视图控制器,将其匹配到StoryBoard中的控件中。

三、 APP使用流程
APP运行的流程一般为,首先执行AppDelegate的代理方法didFinishLaunching,进入启动页,判断是否是首次使用APP,如果是进入欢迎页,否则直接验证广告页验证,进而进入加载广告页,最后进入首页。具体流程图如下:

我的框架也是根据这个流程搭建。
结语
战战兢兢,如履薄冰,望再接再厉,下为工程托管地址,EVNEstorePlatform GitHub,如果觉得有帮助,请不要吝啬点赞,可以在GitHub给个star,O(∩_∩)O谢谢......
本文已在版权印备案,如需转载请在版权印获取授权。
获取版权
网友评论
代码框架(项目框架),比如你要做一个具有某个用途的App(例如:百度地图APP),那么实现这个APP,你需要搭建一个项目(项目会包含,代码和资源文件,资源文件包括,图片、文件等),这个项目的结构规则,就是这个项目的框架。
直接解释什么是框架,我也不知道如何组织语言。但是通过解释框架的作用,来让你明白什么是框架,或许更容易些。如果将框架比作是书架,书架就是用来规整书籍的一个东西。那么代码的框架,就是用来规整你的项目代码的一个东西。这个框架可以是什么样子呢?这个你就需要多看看了。比如,一个很简单的框架,像作者说的那样,他的项目有首页、购物车、个人中心组成。那么你在搭建这个框架前,脑中就会有如何搭建的想法。那么你脑中搭建的结构规则,到最后实现完成,然后你的那个项目文件的实现结构规则,就是这个项目的框架。实现一个项目可以有多种思路,当然也会出现不同的框架结构。因为你的结构规则会不同。下面给俩个猜测。
第一种:比如按照模块来搭建
主项目,主项目中,除了有你通过开发软件,如Xcode,创建一个项目默认的那些文件外。你可能会自定义一下工具类,基类,导航、标签控制器等,然后里边包括3个大文件夹,分别是首页文件夹、购物车文件夹
个人中心文件夹,每个文件夹下如果按照MVC架构模式来,则,每个模块下包含各自模块的代码和资源文件。
第二种:比如你打算按照逻辑结构来搭建。
先来说下,为什么会有这种想法。
如果你觉得,可能在你首页、购物车、个人中心中,有些模块的界面样式、功能实现、都会存在相同或者相通的情况。那么,按照逻辑来划分,或许更便于你对代码的规划和处理。比如:首页中某个商品展示图下,会有加入购物车的按钮,在首页就需要进入购物车页面。个人中心中,也有进入购物车列表的一个按钮。那么,如果按照第一种模块区分的话,购物车列表及它所涉及到的数据、图片、文件等,是不是同时出现在了首页模块、购物车模块、和个人中心模块。这样,你按照第一种方式划分,如果你只把相关东西都放在购物车模块下,会不会出现查找时逻辑的混乱呢。
这样,你是不是会考虑要按照逻辑来划分了呢?
这样的话,你可能会更趋向于,细化每个功能,然后按照逻辑搭建你的框架。比如:整个项目,除了一些通用的基类、工具累,你再细分为,图片展示功能块(其下,继续细分到每个地方的图片展示如:首页图片展示,个人中心图片展示等),购物车列表(其下,继续细分如,购物车编辑、商品收藏、店铺模块等)。依此类推,具体情况,看具体需求。
通过例子和实际接触过的项目,更容易理解。那是因为,在你的脑中,如果有了足够的信息,那么你自然能有更清晰、更明确的判断。
学习的意义是什么?我们每个人都出生的时候都有自己的一个思想,学习,是为了让我们知道更多的思想,当我们脑中有了足够多的思想,总贵是会对我们判断和处理事物有帮助的。
自己都懒的写文章,在这里回复都写成一篇文章了。哈哈哈。如果觉得有用,就个这个作者一个赞吧。我是不是很伟大啊。哈哈哈。
1.每个模块的storyboard都放到各模块的文件夹下,不要放在同一个文件夹,好处:方便查找,如果模块迁移或做成库的时候只需要拷贝整个模块文件夹
2.Models这个文件夹存放哪些文件?按照你的说法是存放MVC中的M,即:业务模块的代码,请问下模型代码也是存放在这个文件夹嘛,如果是的话等于存放了业务和模型的文件,建议分开
3.如果项目有通用的业务代码,不知道你存放到哪个文件夹
4.加入首页模块很大,里面包含很多子模块,那么首页模块下Controllers、Models、Views、Others都可能会有大量的文件,这对查找和分层都很不利,是否考虑过再建立子模块文件夹
5.是否把Tools这里面的常用的通用的工具类做成库的形式,Tools这个文件夹只存放针对此项目的工具类
6.OthersThirdLibs这个文件夹是否可以在详细划分,比如有些是源码引用的,有些是.a、.framework、.bundle等方式引用的
7.没看到项目的数据库、网络请求、资源文件、通用基类等的划分
8.至于xib、storyboard、代码布局的选择,现在已经不推荐代码布局了,理由
1)不熟悉的人写得慢,调试慢,不够直观
2)接手成本高,难以快速理解到你的布局,需要慢慢构想才能接手
现在普遍建议多个storyboard+多个xib,一般分工是一个人负责一个或多个模块,一般不会造成合并冲突
9.如果多个模块有通用业务,放在哪里??
10.如果发布环境配置或证书有多个,建议创建多个target
欢迎订阅《iOS与swift学习之路》https://toutiao.io/subjects/35291