项目文件层次结构

开发是个持续性的过程,无论项目大小,都需要一套严格的开发规范。遵守规范的好处,自然不用多说,我只想就项目开发中的代码文件结构谈谈自己的理解。

先来看看下面这张图吧,这是公司目前的一个项目,框架是我搭建的,在项目启动前期,我将文件分为如下六大类:(注明:YZ是项目的缩写前缀)

YZUser代码文件结构

1、AppDelegate

放置AppDelegate文件,有时候项目会需要自定义自己的AppDelegate来处理更多的消息通知类的东西。

2、Main

主要放的是项目的每个模块对应的代码。因为本项目是用户端和企业端互相切换身份而共存的,所以Main下面我分为:Company和User,并在相应目录下新增各自的业务功能页面

3、Common

是项目中通用的模块,Model & View & VC的集合。

4、Expand

放置的是宏定义、封装好的网络和工具、分类、常量定义等。其中就Const和Macros文件夹下子目录做介绍:
1)Const:该文件夹下放置了YZConst类, 定义了App相关的常量和通知、userDefault名称
2)Macros:包含YZHeader.h、YZNetUrlConfig.h、YZDefine.h、YZConfig.h四个头文件。前两个分别是添加常用头文件需要#import的类和定义所有的网络请求地址,YZDefine.h和YZConfig.h两个头文件定义的东西,详见如下:

//
//  YZDefine.h
//  YZUser
//
//  Created by shuni on 2017/5/27.
//  Copyright © 2017年 shuni. All rights reserved.
//  定义常用方法和常量

#ifndef YZDefine_h
#define YZDefine_h

#define WEAKSELF __weak typeof(self) weakSelf = self;

//测试模式 true,正式上线模式 false
#define DEBUG_MODE true

#if DEBUG_MODE
#define DebugLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
#define DebugLog( s, ... )
#endif

/*
 *  Singleton
 */
//单例对象定义
#define DEFINE_SINGLETON_FOR_HEADER(className) \
\
+ (className *)shared##className;
//单例对象实现
#define DEFINE_SINGLETON_FOR_CLASS(className) \
\
+ (className *)shared##className { \
static className *shared##className = nil; \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
shared##className = [[self alloc] init]; \
}); \
return shared##className; \
}

/*
 *  Standard UserDefaults
 */
#define kStandardUserDefaults                   [NSUserDefaults standardUserDefaults]
#define kStandardUserDefaultsObject(_KEY)       [kStandardUserDefaults objectForKey:_KEY]
#define kSaveStandardUserDefaults(_O,_K)        [kStandardUserDefaults setObject:_O forKey:_K]
#define kRemoveStandardUserDefaults(_K)         [kStandardUserDefaults removeObjectForKey:_K]
#define kStandardUserDefaultsSync               [kStandardUserDefaults synchronize]

/*
 *  UIColor
 */
#define UIColorFromRGB(rgbValue)                [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
#define UIColorFromRGBA(rgbValue, _A)           [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:_A]
#define kColorWithRGB(_R,_G,_B)                 ((UIColor *)[UIColor colorWithRed:_R/255.0 green:_G/255.0 blue:_B/255.0 alpha:1.0])
#define kColorWithRGBA(_R,_G,_B,_A)             ((UIColor *)[UIColor colorWithRed:_R/255.0 green:_G/255.0 blue:_B/255.0 alpha:_A])

/*
 *  Screen size
 */
#define kScreenWidth                            [UIScreen mainScreen].bounds.size.width
#define kScreenHeight                           [UIScreen mainScreen].bounds.size.height

/*
 *  App info
 */
#define kAppDisplayName                         [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]
#define kAppVersion                             [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]
#define kAppIdentifier                          [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]
#define kAppBuildVersion                        [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]

#endif /* YZDefine_h */
//
//  YZConfig.h
//  YZUser
//
//  Created by shuni on 2017/5/27.
//  Copyright © 2017年 shuni. All rights reserved.
//  定义全局变量、Block和枚举类型

#ifndef YZConfig_h
#define YZConfig_h

/*
 * 全局变量定义
 */
//默认字体
static NSInteger NavBarRightTitleFont = 14;

//默认高度
static NSInteger NavPortraitHeight = 64;
static NSInteger NavPortraitStatusHeight = 20;
static NSInteger NavPortraitNoStatusHeight = 44;
static NSInteger NavLandscapeHeight = 32;
static NSInteger TabBarHeight = 49;

//获取验证码倒计时间隔
static int kGetCodeTime = 60;      

//录制默认最大最时长
static float kYZMinRecordTime = 6;      
static float kYZMaxRecordTime = 10;     

//上传的视频限制
static float kYZUploadMaxTime = 60;     //上传的视频最长视频
static float kYZUploadMinWidth = 720;   //上传的分辨率最低提醒
static float kYZUploadMaxBuff = 200;    //上传视频大小限制

//整个水印的高/宽比
static float kYZWatermarkComplateHWScale  = 2277.0/1280.0;  


/*
 * Block定义
 */
typedef void(^YZNetCompletionHandler)(NSURLResponse *response, id responseObject);
typedef void(^YZNetErrorCompletionHandler)(NSURLResponse *response, id responseObject, NSError * error);
typedef void(^YZNetUploadCompetionHandler)(NSURLResponse *response, id responseObject);
typedef void(^YZNetErrorUploadCompetionHandler)(NSURLResponse *response, id responseObject, NSError * error);
typedef void(^YZNetDownloadCompetionHandler)(NSURLResponse *response, NSURL *filePath);
typedef void(^YZNetErrorDownloadCompetionHandler)(NSURLResponse *response, NSURL *filePath, NSError * error);
typedef void(^YZCommonToolVedioCompletionHandler)(NSURL *assetURL, NSError *error, BOOL isVideoAssetvertical);

typedef void(^YZMyHeaderItemSelectedBlock)();
typedef void(^YZPositionCellSelectedBlock)();
typedef void(^YZSendResumeBlock)(UIButton *sendResumeBtn);
typedef void(^YZGotoChatBlock)(UIButton *chatBtn);
typedef void(^YZSignUpBlock)(UIButton *signupBtn);
typedef void(^YZShowLocationInMapBlock)();
typedef void(^YZShowCompanyInfoBlock)();
typedef void(^YZEmptyViewGotoPositionBlock)();

typedef void(^YZVideoChangedBlock)();
typedef void(^YZFinishedCropImagesBlock)(NSArray *images);
typedef void(^YZUnInterviewBtnSelectedBlock)();
typedef void(^YZEndedBtnSelectedBlock)();
typedef void(^YZPositionTypeViewHideBlock)(NSArray *selectedPostionArray);
typedef void(^YZResumeListClickBlock)();
typedef void(^YZPositionDetailPublisherViewCallBlock)();
typedef void(^YZPositionDetailPublisherViewArrowBlock)();
typedef void(^YZNetToolInitConfigFinishBlock)();
typedef void(^YZStartMakeResumeVCPlayVideoBlock)();
typedef void(^YZStartMakeResumeVCStopVideoBlock)();

typedef void(^YZTalentGenderViewSelItemBlock)(NSString *itemName);
typedef void(^YZTalentCityViewSelItemBlock)(NSDictionary *provinceDic, NSDictionary *areaDic);
typedef void(^YZClickChatBtnPopViewBtnClickBlock)();
typedef void(^YZChoosePostVCSelectedItemBlock)(NSString *positionId);

//刷新企业基础信息回调
typedef void(^YZReloadCompanyInfoComplete)();

//职位详情的初始化完成回调
typedef void(^YZResumeDetailVCInitComplete)();
typedef void(^YZCreatePostInitComplete)();


/*
 * 枚举类型定义
 */
typedef NS_ENUM(NSInteger, YZBarItemPostion) {
    YZBarItemPostionLeft = 0,
    YZBarItemPostionRight
};

//网络状态
typedef NS_ENUM(NSInteger, YZNetReachabilityStatus) {
    kYZNetReachabilityStatusUnknown = -1,
    kYZNetReachabilityStatusNotReachable,
    kYZNetReachabilityStatusReachableViaWWAN,
    kYZNetReachabilityStatusReachableViaWiFi
};

//网络状态回调Block
typedef void(^YZNetReachabilityStatusComplete)(YZNetReachabilityStatus netStatus);

typedef NS_ENUM(NSUInteger, YZUserInfoType) {
    kYZUserInfoUID = 1,
    kYZUserInfoUserName,
    kYZUserInfoAvatarImg,
    kYZUserInfoResumeID,
    kYZUserInfoAccessToken,
    kYZUserInfoUserPhone,
    kYZUserInfoUserType,
    kYZUserInfoUserRequestURL,
    kYZUserInfoRongCloudToken
};

typedef NS_ENUM(NSUInteger, YZCompanyInfoType) {
    kYZCompanyInfoID = 1,    //公司ID
    kYZCompanyInfoName,      //公司名称
    kYZCompanyInfoInfo,      //公司介绍
    kYZCompanyInfoEmail,     //公司邮箱
    kYZCompanyInfoType,      //公司type
    kYZCompanyInfoAreaId,    //公司区域ID
    kYZCompanyInfoProvName,  //公司的省
    kYZCompanyInfoCityName,  //公司市
    kYZCompanyInfoAddress,   //公司详细地址
    kYZCompanyInfoState,     //公司审核状态(状态0:审核中,1:正常,2:封号,3未通过)
    kYZCompanyInfoJobCount,  //公司发布岗位数
    kYZCompanyInfoUserAvater,//公司头像
    kYZCompanyInfoUserName,  //公司注册时填写的用户名
    kYZCompanyInfoLinkCount  //公司已与用户聊天个数
};

typedef NS_ENUM(NSUInteger, YZCompanyReviewState) {
    YZCompanyInReview = 0,  //审核中
    YZCompanyInNormal,      //正常
    YZCompanyInBlock,       //封号
    YZCompanyInFail         //未通过
};

typedef NS_ENUM(NSUInteger, YZConfigType) {
    YZConfigPostArray = 1,      //职位
    YZConfigSalary,             //薪资
    YZConfigDegree,             //学历
    YZConfigSpecialtyTags,      //个人标签和职位诱惑
    //公共的配置configBase
    YZConfigShareToFriend,      //app分享给好友
    YZConfigShareToZone,        //app分享到朋友圈/QQ空间
    YZConfigLoginShare,         //第三方登陆和分享是否全部显示,0不开启,1全部显示
    YZConfigCurrentVersion,     //服务器版本地址
    YZConfigUpgradeVersionUrl,  //升级的网址
    YZConfigShouldForceUpgrade, //强制升级
    YZConfigUpgradeDesc,        //升级描述
    YZConfigRouter,             //跳转url
    YZConfigBackgroundMusic,    //视频背景音乐
    YZConfigCompanyLinkLimit,   //企业与用户聊的限制
    YZConfigUserLookLimit       //用户查看职位的限制
};

typedef NS_ENUM(NSUInteger, YZMimeType) {
    kYZMimeTypeImgPng = 1,  //png格式
    kYZMimeTypeImgJpg,      //jpg格式
    kYZMimeTypeVideoMov,    //mov格式
    kYZMimeTypeVideoMp4     //mp4格式
};

typedef NS_ENUM(NSUInteger, YZPrivateAuth) {
    YZAuthorized = 1,  //用户允许
    YZDenied,          //用户拒绝
    YZNotDetermined    //用户尚未选择
};

typedef NS_ENUM(NSUInteger, YZLanguage) {
    YZLanguageEn = 1,  //英文
    YZLanguageTC,      //繁体中文
    YZLanguageCN       //简体
};

typedef NS_ENUM(NSUInteger, YZVideoDealType) {
    YZVideoAddWater = 1 ,  //增加水印
    YZVideoCrop,           //裁剪视频
    YZVideoMontage         //视频拼接
};

//录像的状态
typedef NS_ENUM(NSUInteger, YZRecordState) {
    kYZRecordNone = 1,
    kYZRecordStart,    //开始录制
    kYZRecordPause,    //暂停录制
    kYZRecordDone      //完成录制
};

//时间戳快速转换为时间字符串
typedef NS_ENUM(NSUInteger, YZQuickFormatType) {
    kYZQuickFormateTypeNone = 0,    //自己定义转换
    kYZQuickFormateTypeYMD,         //年月日   2010-09-02
    kYZQuickFormateTypeMD,          //月日     09-02
    kYZQuickFormateTypeYMDTime,     //年月日时间 2010-09-02 05:23:17
    kYZQuickFormateTypeTime,        //时间    05:23:17
    kYZQuickFormateTypeMDTime       //月日时间 09-02 05:23
};

//popup的消失动画
typedef NS_ENUM(NSUInteger, YZPopupviewAnimation) {
    kYZPopAnimationNone = 1,    //无动画直接消失
    kYZPopAnimationPopup,       //上划弹出
    kYZPopAnimationScale,       //缩放直至消失
};

//职位类型
typedef NS_ENUM(NSUInteger, kYZPositionType) {
    kYZPositionPartTime,    //兼职
    kYZPositionFullTime,    //全职
    kYZPositionAnnouncement //通告
};

//职位发布人类型
typedef NS_ENUM(NSUInteger, kYZPositionPublisherType) {
    kYZPersonalPublisher,   //个人
    kYZEnterprisePublisher  //企业
};

//录制的方案
typedef NS_ENUM(NSUInteger, YZRecordType) {
    kYZRecordVedio = 1,    //录制
    kYZChangeVedio         //重录
};

//图片裁剪类型
typedef NS_ENUM(NSUInteger, PhotoClipType) {
    PhotoClipTypeCircle = 0,
    PhotoClipTypeSquare
};

//已投递的职位状态
typedef NS_ENUM(NSUInteger, YZPostedPositionStatusType) {
    kYZUninterviewPosition,  //待面试
    kYZEndedPosition         //已结束
};

//审核状态
typedef NS_ENUM(NSUInteger, YZResumeState) {
    kResumeStatePass = 1,   //审核通过
    kResumeStateinReview,   //审核中
    kResumeStateFail        //审核未通过
};

//反馈类型
typedef NS_ENUM(NSUInteger, YZFeedBackType) {
    kYZFeedBackSuggest = 1,
    kYZFeedBackBUG,
    kYZFeedBackOther
};

//用户身份
typedef NS_ENUM(NSUInteger, YZUserType) {
    kYZUsrTypeNone = 0,     //没有选择用户身份
    kYZUserType,            //用户版
    kYZCompanyType          //企业版
};

typedef NS_ENUM(NSUInteger, YZBannerType) {
    kCommonWebType = 1, //普通跳转网页
    kPostDetailType,    //职位详情
    kResumeDetailType,  //简历详情
    kCreateResumeType   //制作或完善简历
};

//选择查看的职位类型
typedef NS_ENUM(NSUInteger, YZPostState) {
    kYZReviewPost = 0,      //审核中
    kYZProcessingPost = 1,  //发布中
    kYZOverPost = 3,        //已结束
    kYZFailedPost = 4       //审核未通过
};

//选择出行导航工具类型
typedef NS_ENUM(NSUInteger, YZTraveToolTypeForNavigation) {
    kYZDriveForNavigation = 0,   //驾车
    kYZBusForNavigation,         //公交
    kYZWalkForNavigation         //步行
};

typedef void(^YZMapNavigationBlock)(YZTraveToolTypeForNavigation type);

#endif /* YZConfig_h */

5、Vender

这部分是用于管理项目中使用到的常被修改和自定义的第三方库。

6、Resource

从名字很容易理解到,就是放项目中用到的资源文件,除开image放置在Assets.xcassets中,预配置的本地音频、plist、json均放在这个目录之下。

当然这是我的个人习惯,每个人都有自己的一套命名和规范,只要足够的清晰都是可以接受的。干净分明的文件结构层次,某种程度上也有助于开发过程中业务功能的分析,便于将封装的工具类剥离业务而独立开来,降低各个模块之间的粘性,从而提高复用性。而且这个过程在搭建项目时就要考虑的,也在一定程度上能反映开发人员是否具有一定的前瞻性和架构思维。目前,这也是我很需要努力的一个方向~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,085评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,652评论 18 139
  • 最近不知道怎么了,做梦梦到的全是吃的。我知道两天时间从51.6kg升到53.5kg是什么概念。可是。我就是控制不了...
    诺米Naomi阅读 195评论 1 4
  • html部分 合理的title、description、keywords:搜索对这三项的权重逐个减小,title值...
    xiao_333阅读 178评论 0 1
  • 乔乔跟我一个学院的,我们考的是文学类专业,报考的学校也在一个大学城。我跟乔乔大一就认识了,当时我们同在本院的学生会...
    七分白阅读 376评论 0 0