Castie!

正态分布, 优劣伴生

北冥有鱼,其名为鲲(kūn)。鲲之大,不知其几千里也;化而为鸟,其名为鹏。鹏之背,不知其几千里也;怒而飞,其翼若垂天之云。是鸟也,海运则将徙于南冥。南冥者,天池也。


北海若曰:“井鼃不可以语于海者,拘于虚也;夏虫不可以语于冰者,笃于时也;曲士不可以语于道者,束于教也。今尔出于崖涘,观于大海,乃知尔丑,尔将可与语大理矣。

iOS 移动端生成工具开发

上个月的一篇移动端面向文档开发一文久违的被编辑推荐到了首页, 也引来了饿了么大神的关注, 虽然最后实力不济未被录用, 但也指明了我前进的方向. 从4月到现在从一个想法到一步步的实现, 感觉自己还是有充足的长进的, 今天我们继续来完善这个项目.

参考链接:

之前有写过一个python脚本的生成工具, 通过读取json文件进行代码的生成, 实际操作中部分使用者反映, json文件的可读性不是很好(明显是不熟悉json语法导致的), 以及需要生成多平台代码, 所以python并不是很熟练的我, 考虑再三还是写一个oc项目一劳永逸. 本文会涉及到一些平时开发并不会特别关注的知识点, 以及该生成工具的代码设计和使用方法.

选择项目类型

第一个脑中闪现的想法就是使用Command Line Tool命令行工具了, 不就是代码生成吗, 还要开启模拟器? 这不是逗咩…

但我们需要读取Template模板文件, 由于模板文件是不可编译的文件, 所以我们并不能直接将其拖入项目中来, 然后我想那就通过相对路径的方法来读取文件吧, 可惜的是我找了一圈都没有获取当前路径的api, 只有sandbox, 沙盒…

我想命令行工具还有沙盒这玩意? 好吧, 我试试通过Bundle进行获取吧, 试了很久获取到的都是null, 无语… 到Stack Overflow上一问, 命令行工具不支持自制Bundle的读取, 好吧, 我认了. 但我感觉这只是一个链接的问题, 应该是可以读取的, 可惜找不到可执行的方法, 无奈只有放弃.

被迫我们只能够选择Single View Application了, 只是万般无奈啊, 好吧, 对世事的妥协不也是生活中的一部分嘛…

选择配置文件

在配置文件上的选择其实比较简单, 既然是oc的项目, 选择读取最为简单的plist是最好的选择. 同时也比较容易配置.

进行了一些简单的配置, 这部分不是很清晰的同学可以前往 http://www.jianshu.com/p/47d565bf200e 进行了解.

配置完plist后我们将之前的模板一起放入bundle并引入工程.

知识点: 放入bundle的文件并不会进行编译, 仅作为资源文件存储.

选择设计模式

对于设计模式来说, 确实是看过不少相关类型的书籍, 一些常用的设计模式也是手到擒来, 这不, 对于代码生成工具, 立马能够想到生成器模式, 哈哈, 是工厂模式和装饰模式.

其实对于这些设计模式的命名其实感觉挺误导人的, 什么责任链咯, 原型什么的, 其实看一遍代码就懂得东西被吹的神神道道, 也是醉了.

通过设计模式的选择后我们创建了SQBuilderSQFileParser, 前者为工厂模式, 后者为装饰模式.

@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

这个其实就没什么好讲的了, 自己去看代码即可, 仅是读取配置参数并动态生成方法的逻辑代码了.

如何使用?

打开终端输入pwd获取user信息,并填入plist配置文件, 并输入其他参数, 进行Run即可将代码生成至桌面. 以后开发的时候只需要关注View层, 其他的都不需要操心啦~~

具体说明可以下载SQTemplate来进行共同探讨.

最近的文章

Web 使用gulp构建前端项目

对于现在的前端开发来说, 比起之前jQuery时期真心方便很多, 自从ES6的更新后, 更是进一步加快了前端开发的脚步, 并有统一天下的趋势, 随之而出的React / React-Native, Vue / Weex (Vue-Native)之流的框架兴起更是降低了前端开发的门槛, 以至于开发者们对大前端时代趋之若鹜.对于现在的前端开发已经不想以前仅靠切图加上HTML+CSS+JS三件套就能够轻松搞定了, 现在三方提供的工具层出不穷, jQuery, Angular, BootStr...…

前端开发继续阅读
更早的文章

iOS 通俗易懂的HTTP网络

去了饿厂面试后了解到了自己计算机基础的薄弱, 非科班出身薄弱也是自然的, 说实话, 我也并不是特别想要往底层深究, 因为越底层的东西越会抽象成服务输送给大众, 就好比自来水, 一般人都不会想要去了解自来水的底层逻辑吧, 但作为开发者, 我们还是得了解下基础的网络概念.序关于HTTP与HTML的发明有个很有趣的插曲, 那就是首个万维网服务器与浏览器是在一台NeXTStep计算机上编写的, 在1997年, Apple收购了NeXTStep Computer并将NeXTStep作为mac O...…

移动开发继续阅读