你的浏览器禁用了JavaScript, 请开启后刷新浏览器获得更好的体验!
首页
热门
推荐
精选
登录
|
注册
iOS 移动端生成工具开发
立即下载
用AI写一个
金额:
1
元
支付方式:
友情提醒:源码购买后不支持退换货
立即支付
我要免费下载
发布时间:2017-08-22
2人
|
浏览:5152次
|
收藏
|
分享
技术:oc
运行环境:xcode
概述
架构代码生成工具
详细
### 一、准备工作 编译环境 xcode 用于生成冗余架构代码, 实现生成零耦合架构 ### 二、程序实现 > 上个月的一篇[移动端面向文档开发](http://www.jianshu.com/p/b35d06cf189a)一文久违的被编辑推荐到了首页, 也引来了饿了么大神的关注, 虽然最后实力不济未被录用, 但也指明了我前进的方向. 从4月到现在从一个想法到一步步的实现, 感觉自己还是有充足的长进的, 今天我们继续来完善这个项目. 之前有写过一个python脚本的生成工具, 通过读取json文件进行代码的生成, 实际操作中部分使用者反映, json文件的可读性不是很好(明显是不熟悉json语法导致的), 以及需要生成多平台代码, 所以python并不是很熟练的我, 考虑再三还是写一个oc项目一劳永逸. 本文会涉及到一些平时开发并不会特别关注的知识点, 以及该生成工具的代码设计和使用方法. #### 选择项目类型 第一个脑中闪现的想法就是使用Command Line Tool命令行工具了, 不就是代码生成吗, 还要开启模拟器? 这不是逗咩... ![](/contentImages/image/jianshu/1229762-633eb57502c60a1f.png) 但我们需要读取Template模板文件, 由于模板文件是不可编译的文件, 所以我们并不能直接将其拖入项目中来, 然后我想那就通过相对路径的方法来读取文件吧, 可惜的是我找了一圈都没有获取当前路径的api, 只有sandbox, 沙盒... 我想命令行工具还有沙盒这玩意? 好吧, 我试试通过Bundle进行获取吧, 试了很久获取到的都是null, 无语... 到Stack Overflow上一问, 命令行工具不支持自制Bundle的读取, 好吧, 我认了. 但我感觉这只是一个链接的问题, 应该是可以读取的, 可惜找不到可执行的方法, 无奈只有放弃. ![](/contentImages/image/jianshu/1229762-6b1e477d06602050.png) 被迫我们只能够选择Single View Application了, 只是万般无奈啊, 好吧, 对世事的妥协不也是生活中的一部分嘛... #### 选择配置文件 在配置文件上的选择其实比较简单, 既然是oc的项目, 选择读取最为简单的plist是最好的选择. 同时也比较容易配置. ![](/contentImages/image/jianshu/1229762-d4c8b910298ae21a.png) ![](/contentImages/image/jianshu/1229762-7df7f7846e1ef1e0.png) 进行了一些简单的配置, 这部分不是很清晰的同学可以前往 [http://www.jianshu.com/p/47d565bf200e](http://www.jianshu.com/p/47d565bf200e) 进行了解. 配置完plist后我们将之前的模板一起放入bundle并引入工程. ![](/contentImages/image/jianshu/1229762-ec6f1235005944b3.png) 知识点: 放入bundle的文件并不会进行编译, 仅作为资源文件存储. #### 选择设计模式 对于设计模式来说, 确实是看过不少相关类型的书籍, 一些常用的设计模式也是手到擒来, 这不, 对于代码生成工具, 立马能够想到生成器模式, 哈哈, 是工厂模式和装饰模式. 其实对于这些设计模式的命名其实感觉挺误导人的, 什么责任链咯, 原型什么的, 其实看一遍代码就懂得东西被吹的神神道道, 也是醉了. 通过设计模式的选择后我们创建了`SQBuilder`和`SQFileParser`, 前者为工厂模式, 后者为装饰模式. ``` @interface SQBuilder : NSObject @property (nonatomic,copy) NSString * user; @property (nonatomic,copy) NSString * prefix; @property (nonatomic,copy) NSString * module; @property (nonatomic,strong) NSDictionary * parameter; @property (nonatomic,strong) NSDictionary * dataList; @property (nonatomic,strong) NSArray * actionList; + (void)runWithFileParser:(NSDictionary *)config success:(void (^)())success failure:(void (^)())failure; - (void)build; @end ``` ``` + (SQBuilder *)builderWithType:(SQBuilderType)builderType { switch (builderType) { case SQBuilderTypeiOS: return [SQBuilder_iOS new]; break; case SQBuilderTypeAndroid: return [SQBuilder_Android new]; break; case SQBuilderTypeNone: return [SQBuilder new]; break; default: break; } } ``` SQBuilder的头文件暴露了和plist中需要配置的属性以及加载SQFileParser文件解析类的方法. 通过工厂模式可以分配创建不同的类. ``` @interface SQFileParser : NSObject + (NSDictionary *)parser_plist_r; + (void)parser_rw:(NSString *)path code:(NSString *)code filename:(NSString *)filename header:(NSString *)header parameter:(NSMutableArray *)parameter; @end ``` ``` [SQBuilder runWithFileParser:[SQFileParser parser_plist_r] success:^{ title = @"Build Finished"; message = @"please view the floder on the desktop"; } failure:^{ title = @"Build Error!!!"; message = @"please enter the right builder type!!"; }]; ``` SQFileParser的头文件暴露了读取不同文件类型的接口, 后续读取Excel表格类型仅需添加新的类型接口即可. #### 创建文件夹 Api ``` NSFileManager * manager = [NSFileManager defaultManager]; NSString * path = [NSString stringWithFormat:@"/Users/%@/Desktop/%@", self.user, self.module]; [manager createDirectoryAtPath:path withIntermediateDirectories:NO attributes:nil error:nil]; ``` oc中创建文件夹的方式, 能找到的就只有这个了, 而且只能读取绝对路径, 但又不能读取当前文件路径, mac机的user每台机器都不一样, 真是坑啊, 像文件读写这种东西还是python写最为稳妥. #### SQFileParser 代码分析 ``` + (NSDictionary *)parser_plist_r { NSBundle * bundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"builder.bundle" ofType:nil]]; return [NSDictionary dictionaryWithContentsOfFile:[bundle pathForResource:@"config/config.plist" ofType:nil]]; } ``` 通过子bundle进行读取/config.plist配置文件, 知识点: 当读取bundle深层结构时需要添加文件路径. ``` + (NSString *)parser_r:(NSString *)filename code:(NSString *)code { NSBundle * bundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"builder.bundle" ofType:nil]]; return [NSMutableString stringWithContentsOfFile:[bundle pathForResource:[NSString stringWithFormat:@"template/%@/%@", code, filename] ofType:nil] encoding:NSUTF8StringEncoding error:nil]; } ``` Templete文件的读取, 和上面的读取plist相同, 并没有什么不同之处. ``` static NSString * code; + (NSString *)replaceThougth:(NSString *)templete parameter:(NSMutableArray *)parameter { __block NSString * temp = templete; [[parameter firstObject] enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) { temp = [templete stringByReplacingOccurrencesOfString:key withString:obj]; }]; [parameter removeObjectAtIndex:0]; if (parameter.count) { [SQFileParser replaceThougth:temp parameter:parameter]; } else { code = temp; } return code; } ``` 写入新文件, 这个就要好好讲讲了, NSString的`stringByReplacingOccurrencesOfString`方法是会返回一个新的更改后的字符串但并不会改变原指针. 但如果需要替换很多处的话就需要链式调用多次, 真是丑, 一个字概括了所有的观点, 所以我在想有什么方法能够避免这个问题呢? 马上想的就是上述递归调用的方法啦, 哈哈. ``` + (void)parser_rw:(NSString *)path code:(NSString *)code filename:(NSString *)filename header:(NSString *)header parameter:(NSMutableArray *)parameter { NSString * arch = [[filename componentsSeparatedByString:@"."]firstObject]; NSString * suffix = [[filename componentsSeparatedByString:@"."]lastObject]; NSString * filename_r = [NSString stringWithFormat:@"%@Template.%@", arch,suffix]; NSString * filename_w = [NSString stringWithFormat:@"%@/%@%@.%@", path,header,arch,suffix]; NSString * template = [SQFileParser parser_r:filename_r code:[code lowercaseString]]; [[SQFileParser replaceThougth:template parameter:parameter] writeToFile:filename_w atomically:YES encoding:NSUTF8StringEncoding error:nil]; } ``` 这个方法是读写一体的, 根据拿到的配置参数, 拼接出输入文件名和输出文件名, 并进行文件的读取和写入. #### SQBuilder 这个其实就没什么好讲的了, 自己去看代码即可, 仅是读取配置参数并动态生成方法的逻辑代码了. #### 如何使用? ![](/contentImages/image/jianshu/1229762-fc74bd0c6d91d2af.png) ![](/contentImages/image/jianshu/1229762-3440afd9c465ff1f.png) 打开终端输入pwd获取user信息,并填入plist配置文件, 并输入其他参数, 进行`Run`即可将代码生成至桌面. 以后开发的时候只需要关注View层, 其他的都不需要操心啦~~ ### 三、运行效果 ![](/contentImages/image/jianshu/1229762-cb7358787483d9d6.png) ### 四、其他补充 ####项目代码结构图 就是上面的使用截图,另外也这里也补充项目截图: ![](/contentImages/image/20170822/2WTrGJ6zmtuDz9M6N8N.png)
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
感谢
0
手机上随时阅读、收藏该文章 ?请扫下方二维码
相似例子推荐
评论
作者
Castie!
5
例子数量
77
帮助
3
感谢
评分详细
可运行:
4.5
分
代码质量:
4.5
分
文章描述详细:
4.5
分
代码注释:
4.5
分
综合:
4.5
分
作者例子
[Animations] 快速上手 iOS10 属性动画
[SceneKit] 不会 Unity3D 的另一种选择
[SpriteKit] 系统框架中Cocos2d-x制作小游戏ZombieConga
[SpriteKit] 制作瓦片地图小游戏
iOS 移动端生成工具开发