首页 > 代码库 > iOS开发架构

iOS开发架构

其实对于“架构”这个词,我觉得是一个很庞大的话题。我刚出道还是一个小菜鸟的时候,一直认为这个话题是对于拥有很多年开发经验的程序员来说的(这里并没一味去认为老程序员就是神的说法,也有部分水货哦,大部分都是大牛吧),毕竟在软件开发这一行业,经验足够深时才有更多的思考和设计。然事情过去一两年之后,自己个人技术也慢慢有所提升,从自己写博客记录个人错误积累经验伊始,我就发现自己停不下来了,真的是停不下来了,那是真真的停不下来了,我不停的给我同学或者技术群推荐我的博客,收到一些人的嘲笑,但是我从未停止过。因为重现的错误我即使忘了也能通过个人博客很快定位并进行修复,我想这就是积累和成长对我最大的帮助吧!

我不知道别人如何理解“架构”的,在跳槽两次之后,看到两家老大和同事的一些代码,自己一直想总结一套属于自己的风格,之前也有总结但只是试用一下还不够全面,今日下午闲着喝了一杯毛尖新茶(老家自产的,博主父亲邮寄而来),新茶的清香在一小段舒服的午觉之后激发了博主的灵感,进行了一下总结,至少先在博客中慢慢的记录一下,以后再不断优化补充。在我眼里:首先就是一个项目整体的框架,然后导入使用的库或者自己封装的库和公共方法,项目文件路径清晰明了,注释和代码都易懂,方便自己和别人协同开发,其次要尽量保持一致的风格,形成公司的开发规范;说白了,就是对该项目有一个模板,别人就是在你这个模板之下填充代码,本地文件存放路径。当然这也只是自己个人对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文件中

[objc] view plain copy
 技术分享技术分享
  1. #import "ModelData.h"  
  2.   
  3. @implementation ModelData  
  4.   
  5. + (ModelData*)itemWithDictionary:(NSDictionary *)dictionary  
  6. {  
  7.     return [[self alloc]initItemWithDictionary:dictionary];  
  8.       
  9. }  
  10.   
  11. - (instancetype)initItemWithDictionary:(NSDictionary *)dictionary  
  12. {  
  13.     self = [super init];  
  14.     if(self)  
  15.     {  
  16.         [self setValuesForKeysWithDictionary:dictionary];  
  17.     }  
  18.       
  19.     return self;  
  20. }  
  21.   
  22. //将id关键字转为Id,将数值字段字符串转为float类型  
  23. - (void)setValue:(id)value forUndefinedKey:(NSString *)key  
  24. {  
  25.     if([key isEqualToString:@"id"])  
  26.     {  
  27.         self.Id = value;  
  28.     }  
  29. }  
技术分享

在model.h文件中,除了一些关键字或者个人想修改的字段值,其他字段都需要和后台保持一一对应,如

[objc] view plain copy
 技术分享技术分享
  1. #pragma mark - 银行卡信息  
  2. @property(nonatomic,retain)NSMutableArray *banks;//平台提供银行数组  
  3. @property(nonatomic,copy)NSString *bank_name;//银行名称  
  4. @property(nonatomic,copy)NSString *bank_branch;//支行名称  
  5. @property(nonatomic,copy)NSString *bank_account;//银行卡号  
  6. @property(nonatomic,copy)NSString *bank_user;// 银行户主 

二、网络请求

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文件,对字体、颜色;屏幕宽、高;通知、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]
#define RGBA(r,g,b,a) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]

#pragma mark - 系统颜色
#define COLOR_S_WHITE [UIColor whiteColor]
#define COLOR_S_CLEAR [UIColor clearColor]
#define COLOR_S_RED [UIColor redColor]
#define COLOR_S_GREEN [UIColor greenColor]
#define COLOR_S_BLUE [UIColor blueColor]
#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_NavigationBlue [UIColor colorWithRed:81.0/255.0 green:174.0/255.0 blue:217.0/255.0 alpha:1]
#define COLOR_C_BackColor [UIColor colorWithRed:234/255.0 green:234/255.0 blue:234/255.0 alpha:1]
#define COLOR_C_GrayColor [UIColor colorWithRed:229/255.0 green:229/255.0 blue:229/255.0 alpha:1]
#define COLOR_C_GreenColor [UIColor colorWithRed:134/255.0 green:204/255.0 blue:200/255.0 alpha:1]
#define COLOR_C_SetBlack [UIColor colorWithRed:35.0/255.0 green:38.0/255.0 blue:41.0/255.0 alpha:1]
#define COLOR_C_Training [UIColor colorWithRed:252/255.0 green:249/255.0 blue:228/255.0 alpha:1]
#define COLOR_C_YunName [UIColor colorWithRed:249/255.0 green:128/255.0 blue:37/255.0 alpha:1]
#define COLOR_C_YunSpace [UIColor colorWithRed:150/255.0 green:206/255.0 blue:208/255.0 alpha:1]
#define COLOR_C_CuXiao [UIColor colorWithRed:232/255.0 green:97/255.0 blue:30/255.0 alpha:1]
// COLOR_C_R204_G204_B204_Alp5
#define COLOR_C_cccccc_Alp5 UIColorFromRGB(0xcccccc,0.5)

#pragma mark - 系统字体
#define FONT_S_5 [UIFont systemFontOfSize:5.0f]
#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_21 [UIFont systemFontOfSize:21.0f]
#define FONT_S_23 [UIFont systemFontOfSize:23.0f]
#define FONT_S_24 [UIFont systemFontOfSize:24.0f]
#define FONT_S_23 [UIFont systemFontOfSize:23.0f]
#define FONT_S_25 [UIFont systemFontOfSize:25.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]
#define FONT_SB_18 [UIFont boldSystemFontOfSize:18.0f]
#define FONT_SB_20 [UIFont boldSystemFontOfSize:20.0f]
2、加载框HUD;提示框Alert都可以进行自定义单独建立类文件;背景灰蒙模糊透明

3、中国省市区下载.plist文件

4、公公方法如:CommonFun、Tool等文件封装提取上下拉加载刷新;lable下划线,不同字体颜色;MD5加密;json字符串转换等公共方法

5、登录用户名的保存,使用NSUserDefault或者沙盒进行保存

6、无数据时提示页面或者重新加载页面

四、第三方平台和类库

1、第三方平台:这些平台使用前提是公司提供账号,千万别使用个人账号。然后去创建应用申请审核,获取AppKey和AppSerect

    (1)支付:支付宝;微信;银联

    (2)分享:微信、QQ、微博

    (3)地图:百度、高德

    (4)二维码

    (5)推送:个推、友盟等

    (6)即时通信:环信、云信等

    (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,则就可以躲过审核

五、公司团队协作

1、代码管理:SVN OR Git;注释和代码风格(尽量形成公司的统一规范)

2、项目管理:(禅道)bug测试提交以及验证复现等;企业邮箱;花瓶抓包;iOS开发者账号

3、接口文档;PC端项目地址;

4、app需求文档;设计图和切图

iOS开发架构