iOS APP框架搭建简析(附GitHub托管Demo)

原文:iOS APP框架搭建简析(附GitHub托管Demo)

奋斗.png
都说“三岁看老”,我在和谐社会中摸爬 打滚了也近三个年头,这不快过年了,今年朋友/发小寻找“心理平衡”的首选对象依旧是哥,看着大家满意而归的身影,荣幸之至!捧一捧凉水扑到脸上,抬头照照镜子打量着依旧“枯瘦如柴”的自己,看着时间给刻下的“抬头纹”,盯着那浑浊但依旧坚定的眼睛,哥想对自己说:“大雁,你可以的,虽然没有以前好配合了,你终有一天会成功的,虽然还很遥远!乖乖,好了,傻B可以写帖子了……”

前言

不管开发任何软件,我们的原则就是尽量做到“高内聚低耦合”。所谓“低耦合”是指软件结构中模块与模块之间的耦合度或关联程度,模块之间接口的调用及实现的复杂度、交互数据的多少等,决定了软件耦合度的高低强弱;所谓“高内聚”是从模块内部功能的层面而言的,模块内部特定功能的代码元素的紧密程度决定了代码内聚性的高低。

网上不乏有所谓“十分钟搭建强壮APP框架”、“快速搭建强壮APP框架”等帖子,且不去讲好坏,总之,实践是检验真理的唯一标准,今天我简单汇报下本人做项目时,框架的搭建流程及注意事项。

框架搭建

框架搭建是个劳神费心的事情,因为在搭建时你要考虑到各种可能,比如:怎么设计使得流程更清晰?怎么设计更易于分工协作?怎么设计更容易快速定位代码模块?怎么保证系统的易扩展性?等等都是我们要提前把握好的。先看下大致效果图如下:

启动图效果.png
最终效果.gif

一、 框架结构

APP的结构一般分为三条线:

  • 一条主框架流程;
  • 一条是用户登录框架流程;
  • 一条其他如广告页、欢迎页等

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

二、 StoryBoard分离

为了配置三方库方便,我使用CocoaPods工程(基于CocoaPods 1.1.1),下为Podfile文件引入的三方库:

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

MainStoryBoard.png

MineCenterStoryBoard.png

在进行故事版分离时,主要是自定义UITabBarController的过程。
首先,根据上面模板图,新建故事版文件;
然后,按照第一节框架结构图,将特定的控制器容器、导航控制器、视图控制器拖入对应的故事版中(StoryBoard文件);
再次,在自定义的UITabBarController中,连接各个模块,在这个过程中UITabBarController起到了应用的连接中枢的作用,为了炫技,哥做了个中间凸起效果,主要的TabBarController代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#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中的控件中。
框架目录.png

三、 APP使用流程

APP运行的流程一般为,首先执行AppDelegate的代理方法didFinishLaunching,进入启动页,判断是否是首次使用APP,如果是进入欢迎页,否则直接验证广告页验证,进而进入加载广告页,最后进入首页。具体流程图如下:
APP流程图.png
我的框架也是根据这个流程搭建。

结语

战战兢兢,如履薄冰,望再接再厉,下为工程托管地址,EVNEstorePlatform GitHub,如果觉得有帮助,请不要吝啬点赞,可以在GitHub给个star,O(∩_∩)O谢谢……