iOS开发架构
来源:互联网 发布:mac cd命令进入文件夹 编辑:程序博客网 时间:2024/06/06 00:42
其实对于“架构”这个词,我觉得是一个很庞大的话题。我刚出道还是一个小菜鸟的时候,一直认为这个话题是对于拥有很多年开发经验的程序员来说的(这里并没一味去认为老程序员就是神的说法,也有部分水货哦,大部分都是大牛吧),毕竟在软件开发这一行业,经验足够深时才有更多的思考和设计。然事情过去一两年之后,自己个人技术也慢慢有所提升,从自己写博客记录个人错误积累经验伊始,我就发现自己停不下来了,真的是停不下来了,那是真真的停不下来了,我不停的给我同学或者技术群推荐我的博客,收到一些人的嘲笑,但是我从未停止过。因为重现的错误我即使忘了也能通过个人博客很快定位并进行修复,我想这就是积累和成长对我最大的帮助吧!
我不知道别人如何理解“架构”的,在跳槽两次之后,看到两家老大和同事的一些代码,自己一直想总结一套属于自己的风格,之前也有总结但只是试用一下还不够全面,今日下午闲着喝了一杯毛尖新茶(老家自产的,博主父亲邮寄而来),新茶的清香在一小段舒服的午觉之后激发了博主的灵感,进行了一下总结,至少先在博客中慢慢的记录一下,以后再不断优化补充。在我眼里:首先就是一个项目整体的框架,然后导入使用的库或者自己封装的库和公共方法,项目文件路径清晰明了,注释和代码都易懂,方便自己和别人协同开发,其次要尽量保持一致的风格,形成公司的开发规范;说白了,就是对该项目有一个模板,别人就是在你这个模板之下填充代码,本地文件存放路径。当然这也只是自己个人对iOS开发架构的理解,有不当之处还望广大的博友给予更好的建议!下面就我自己反思总结对整体项目开发架构进行设计:
一、MVC模式
MVVM、MVP模式博主暂时用的少,大家可以给博主一些好文章钻研,感激不尽!
1、创建基类BaseViewController和BaseNavigationController(可根据需要),设定导航栏颜色(项目主题色),以及返回键样式,还可判断网络,如:
- (void)viewDidLoad { [super viewDidLoad]; //设置左边 返回按钮 [self setLeftButton];}- (void)setLeftButton{ UIView *navibarView = [[UIView alloc]initWithFrame:CGRectMake(0, 0,Wi,64)]; navibarView.backgroundColor = COLOR_C_NavigationRED; [self.view addSubview:navibarView]; //导航栏的返回按钮只保留那个箭头,去掉后边的文字,最简单且没有副作用的方法就是 [[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60) forBarMetrics:UIBarMetricsDefault];}- (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; self.navigationController.navigationBar.hidden = NO; [self.navigationController.navigationBar setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIColor whiteColor],NSForegroundColorAttributeName,nil]]; [self.navigationController.navigationBar setBackgroundImage:UIIMAGE(@"") forBarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault]; [self.navigationController.navigationBar setShadowImage:[UIImage new]]; self.navigationController.navigationBar.tintColor = [UIColor whiteColor]; [self.navigationController.navigationBar setBarTintColor:COLOR_C_NavigationRED]; self.view.backgroundColor = COLOR_C_BackColor; //返回按钮 UIBarButtonItem *item = [[UIBarButtonItem alloc]initWithImage:UIIMAGE(@"") style:UIBarButtonItemStylePlain target:self action:@selector(goBack)]; [[UINavigationBar appearance] setTintColor:[UIColor whiteColor]]; self.navigationItem.backBarButtonItem = item; //检测网络 [self getNetWorkstate];}- (void)goBack{ [self.navigationController popViewControllerAnimated:YES];}#pragma mark - 网络检测- (void)getNetWorkstate{ AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager]; [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { switch (status) { case AFNetworkReachabilityStatusUnknown: NSLog(@"未识别的网络"); break; case AFNetworkReachabilityStatusNotReachable:{ NSLog(@"不可达的网络(未连接)"); SHOWALERT(@"未连接网络!"); break;} case AFNetworkReachabilityStatusReachableViaWWAN: NSLog(@"2G,3G,4G...的网络"); break; case AFNetworkReachabilityStatusReachableViaWiFi: NSLog(@"wifi的网络"); break; default: break; } }]; [manager startMonitoring];}
2、UITabBarController根据需求是否需要自定义
3、View控件类别进行方法的添加(怎么处理看你需求了),方便处理使用
4、Model创建一个即可,无需一个数据对象创建一个model
setValue:(id)value forUndefinedKey:(NSString *)key方法进行修改,同时此方法可以过滤掉不存在的键值对而防止崩溃,或者修改你手动的映射key值不同的值
在model.m文件中
在model.h文件中,除了一些关键字或者个人想修改的字段值,其他字段都需要和后台保持一一对应,如
二、网络请求
1、AFN基础之上对GET、POST等方法再次封装(创建一对.h和.m类文件;示例中包含伪代码,主要讲述思路)
#pragma mark - GET请求- (void)get:(NSString *)url result:(void (^)(NSDictionary *responseData))result{ AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; //设置请求头 [self setHeader:manager]; [manager GET:url parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"url====%@\n返回数据%@",url,responseObject); if (result) {// result(responseObject); if(responseObject[@"code"] == 408)//session过期 { //获取登录用户名账号和密码 User *user = [User getUserInfo]; //后台隐藏做登录操作重新获取session或者token(一般设置半小时过期,即app放置半小时或者后台运行不作操作,这是再操作和session有关的接口全都获取不到数据,页面为空) int code = [self loginRequest]; if (code == 400){ //登陆成功,重新将该请求发送一次(此处可根据请求方法名封装成一个方法去做此处理操作) [self get:url result:result]; } } } } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"error ==%@",error); //请求超时 if (error.code == -1001) { //1、获取当前viewController UIViewController *viewController = [[CommFun singleton] getCurrentVC]; //2、隐藏加载框 [MBProgressHUD hideHUDForView:viewController.view animated:YES]; //3、弹出提示:请求超时 SHOWALERT(@"请求超时,请刷新后再试!", viewController); } }];}#pragma mark - POST请求- (void)post:(NSString *)url postData:(NSDictionary *)data result:(void (^)(NSDictionary *responseData))result{ AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; //设置请求头 [self setHeader:manager]; [manager POST:url parameters:data progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {// NSLog(@"url====%@\n返回数据%@",url,responseObject); if (result) { result(responseObject); } } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"error ==%@",error); //请求超时 if (error.code == -1001) { //1、获取当前viewController UIViewController *viewController = [[CommFun singleton] getCurrentVC]; //2、隐藏加载框 [MBProgressHUD hideHUDForView:viewController.view animated:YES]; //3、弹出提示:请求超时 SHOWALERT(@"请求超时,请刷新后再试!", viewController); } }];}- (void)setHeader:(AFHTTPSessionManager *)manager{ // 上传JSON格式 manager.requestSerializer = [AFJSONRequestSerializer serializer]; //声明返回的数据格式// manager.responseSerializer = [AFHTTPResponseSerializer serializer]; //序列化 [manager.responseSerializer setAcceptableContentTypes: [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", @"charset=utf-8",@"text/css", nil]]; //设置超时时间 [manager.requestSerializer willChangeValueForKey:@"timeoutInterval"]; manager.requestSerializer.timeoutInterval = 60.f; [manager.requestSerializer didChangeValueForKey:@"timeoutInterval"];}
2、token或者session过期重新登录获取且对该请求再发送一次,代码示例如上
3、服务器和本地域名,以及所有请求的URL使用宏定义(创建一个.h文件),方便修改
// 服务器url//#define SERVICENET @"http://192.168.1.12:8080/ABC/“#define SERVICENET @"http://192.168.1.11:8080/ABC/“// 带token#define SERVICENETTOKEN [NSString stringWithFormat:@"%@?access_token=%@",SERVICENET,(NSString *)Token]#define Token ((AppDelegate *)[[UIApplication sharedApplication] delegate]).access_token/********** 用户网络接口 *********/// 用户登录接口#define LOGIN [NSString stringWithFormat:@"%@common/token",SERVICENET]
4、检查网络
AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager]; [mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { // 当网络状态发生改变的时候调用这个block switch (status) { case AFNetworkReachabilityStatusReachableViaWiFi: { [[NSNotificationCenter defaultCenter]postNotificationName:@"networkOk" object:nil]; } break; case AFNetworkReachabilityStatusReachableViaWWAN: { [[NSNotificationCenter defaultCenter]postNotificationName:@"networkOk" object:nil]; } break; case AFNetworkReachabilityStatusNotReachable: { [[NSNotificationCenter defaultCenter]postNotificationName:@"networkNo" object:nil]; } break; case AFNetworkReachabilityStatusUnknown: { [[NSNotificationCenter defaultCenter]postNotificationName:@"networkNo" object:nil]; } break; default: break; } }]; // 开始监控 [mgr startMonitoring];
三、公共方法
1、建立pch文件,对字体、颜色;屏幕宽、高;系统版本;iPhone还是iPad设备等宏定义;通知、NSUserDefault系统单例缩写建立.h文件;
#pragma mark - 十六进制颜色的RGB转换#define UIColorFromRGB(rgbValue,alp) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:alp]#pragma mark - 系统颜色#define COLOR_S_WHITE [UIColor whiteColor]#define COLOR_S_CLEAR [UIColor clearColor]#define COLOR_S_YELLOW [UIColor yellowColor]#define COLOR_S_RED [UIColor redColor]#define COLOR_S_BLUE [UIColor blueColor]#define COLOR_S_GREEN [UIColor greenColor]#define COLOR_S_BLACK [UIColor blackColor]#define COLOR_S_LIGHTGRAY [UIColor lightGrayColor]#define COLOR_S_DRAKGRAY [UIColor darkGrayColor]#define COLOR_S_GRAY [UIColor grayColor]#define COLOR_S_GROUPTABLEVIEW_BG [UIColor groupTableViewBackgroundColor]#pragma mark - 自定义颜色// 基调背景色#define COLOR_C_eeeeee UIColorFromRGB(0xeeeeee,1.0)#define COLOR_C_fbfbfb UIColorFromRGB(0xfbfbfb,1.0)
#pragma mark - 系统字体#define FONT_S_8 [UIFont systemFontOfSize:8.0f]#define FONT_S_10 [UIFont systemFontOfSize:10.0f]#define FONT_S_11 [UIFont systemFontOfSize:11.0f]#define FONT_S_12 [UIFont systemFontOfSize:12.0f]#define FONT_S_13 [UIFont systemFontOfSize:13.0f]#define FONT_S_14 [UIFont systemFontOfSize:14.0f]#define FONT_S_15 [UIFont systemFontOfSize:15.0f]#define FONT_S_16 [UIFont systemFontOfSize:16.0f]#define FONT_S_17 [UIFont systemFontOfSize:17.0f]#define FONT_S_18 [UIFont systemFontOfSize:18.0f]#define FONT_S_20 [UIFont systemFontOfSize:20.0f]#define FONT_S_24 [UIFont systemFontOfSize:24.0f]#define FONT_S_25 [UIFont systemFontOfSize:25.0f]#define FONT_S_40 [UIFont systemFontOfSize:40.0f]#pragma mark - 系统字体(加粗)#define FONT_SB_10 [UIFont boldSystemFontOfSize:10.0f]#define FONT_SB_12 [UIFont boldSystemFontOfSize:12.0f]#define FONT_SB_14 [UIFont boldSystemFontOfSize:14.0f]#define FONT_SB_15 [UIFont boldSystemFontOfSize:15.0f]#define FONT_SB_16 [UIFont boldSystemFontOfSize:16.0f]
#ifdef DEBUG# define XGLog(fmt, ...) NSLog((@"[文件名:%s]\n" "[函数名:%s]\n" "[行号:%d] \n" fmt), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)#else# define XGLog(...)#endif
自定义输出Log
2、加载框HUD;提示框Alert都可以进行自定义单独建立类文件;背景灰蒙模糊透明
3、中国省市区下载.plist文件
4、公公方法如:CommonFun、Tool等文件封装提取上下拉加载刷新;lable下划线,不同字体颜色;MD5加密;json字符串转换等公共方法
5、登录用户名的保存,使用NSUserDefault或者沙盒进行保存
// 保存用户信息+ (void)saveUser:(XGUserModel *)user { BOOL isSucc= [NSKeyedArchiver archiveRootObject:user toFile:UserPath]; if(isSucc){ XGLog(@"用户信息保存成功"); } else { XGLog(@"用户信息保存失败"); }}// 读取用户信息+ (XGUserModel *)readUser { NSFileManager *manager = [NSFileManager defaultManager]; BOOL isfile = [manager fileExistsAtPath:UserPath]; if (isfile) { XGUserModel *user = [NSKeyedUnarchiver unarchiveObjectWithFile:UserPath]; return user; }else { return nil; }}或者
//登陆成功 保存当前登录时间,以及用户,密码 NSDate *date = [NSDate date]; [[NSUserDefaults standardUserDefaults] setObject:date forKey:@"lastDate"]; [[NSUserDefaults standardUserDefaults] setObject:@"1" forKey:@"login"]; [[NSUserDefaults standardUserDefaults] setObject:tf1.text forKey:@"account"]; [[NSUserDefaults standardUserDefaults] setObject:tf2.text forKey:@"password"]; //保存用户id [ClientBaseData singleton].user_id = dic[@"data"][@"user_id"]; [[NSUserDefaults standardUserDefaults] setObject:dic[@"data"][@"user_id"] forKey:Userid]; [GeTuiSdk bindAlias:dic[@"data"][@"user_id"]];
6、无数据时提示页面或者重新加载页面,以美团为例(配置app的logo,刷新给定一个button,提示给定一个label)
7、判断字符串,对象,数组,字典是否为空
//字符串是否为空#define kStringIsEmpty(str) ([str isKindOfClass:[NSNull class]] || str == nil || [str length] < 1 ? YES : NO )//数组是否为空#define kArrayIsEmpty(array) (array == nil || [array isKindOfClass:[NSNull class]] || array.count == 0)//字典是否为空#define kDictIsEmpty(dic) (dic == nil || [dic isKindOfClass:[NSNull class]] || dic.allKeys == 0)//是否是空对象#define kObjectIsEmpty(_object) (_object == nil \|| [_object isKindOfClass:[NSNull class]] \|| ([_object respondsToSelector:@selector(length)] && [(NSData *)_object length] == 0) \|| ([_object respondsToSelector:@selector(count)] && [(NSArray *)_object count] == 0))
四、第三方平台和类库
1、第三方平台:这些平台使用前提是公司提供账号,千万别使用个人账号。然后去创建应用申请审核,获取AppKey和AppSerect
(1)支付:支付宝;微信;银联
(2)分享:微信、QQ、微博(ShareSDK、友盟等)
(3)地图:百度、高德
(4)二维码:ZBar 和 ZXing
(5)推送:个推、友盟等
(6)即时通信:环信、云信等,也可自己公司研究Socket,但是成本要高一些
(7)热更新:JSPatch
(8)app用户下载量统计
(9)crash错误日志:BugHD等
(10)ipa打包测试上传:蒲公英、fir等
2、第三方类库:AFN(网络请求)、MBProgressHUD(加载框)、MJRefresh(上下拉加载刷新)、SDWebImage(加载图片)等常用类库
(1)屏幕适配使用Masonary(纯代码) OR Auto-Layout,或者两者混用
(2)手动导入库 OR 使用Pods(安装检测ruby环境,淘宝镜像)
(3)SQLite OR CoreData
3、强制更新(苹果审核不过):但是可实现此技术;服务器给一个接口记录一个版本,app上架之前和服务器保持一个版本,审核之后将服务器版本比当前版本+1,则就可以躲过审核
4、Base64、bejson在线解析等,查看返回数据更加直观
五、公司团队协作
1、代码管理:SVN OR Git;注释和代码风格(尽量形成公司的统一规范)
2、项目管理:(禅道)bug测试提交以及验证复现等;企业邮箱;花瓶抓包;iOS开发者账号
3、接口文档;PC端项目地址;
4、app需求文档;效果图和切图
最后,博主给出一个项目工程划分模块的目录,仅供参考:
- IOS应用开发架构
- IOS应用开发架构
- IOS应用开发架构
- iOS app开发架构
- IOS应用开发架构
- iOS开发~架构图
- iOS开发架构
- 九十一、iOS应用程序开发架构
- IOS开发之系统架构
- iOS开发工程架构设计
- iOS大型项目开发架构
- iOS开发知识架构图
- iOS开发--iOS应用架构谈 开篇
- iOS开发系列--iOS应用架构谈
- 移动开发(IOS) – iOS系统架构
- 【iOS开发】iOS移动端架构
- iOS开发项目架构浅谈:iOS架构设计与分层
- IOS的网络开发架构说明
- window 下python2.7与python3.5两版本共存设置
- LIBSVM与LIBLINEAR(三)
- 推理
- CF gym: Feel Good(单调栈)
- centos7安装并配置nginx+php
- iOS开发架构
- C++ 栈和队列的使用
- BZOJ P3504[Cqoi2014]危桥
- hdu 1251 (Trie 树)
- 清空Qtablewiget 表格的内容
- Android视图SurfaceView的实现原理分析
- java程序中,如何安全的结束一个正在运行的线程
- 激光雷达:Pandar 40
- 文章标题