• 为什么唱iOS 6.0选择Mantle


    近来的iOS的6.0版本号已经成功上线了。

    18人月的投入,2500个commit,几十万行的代码改动。

    唱吧iOS已经从内至外焕然一新,感谢一起并肩作战的小伙伴们。

    6.0一个非常重大的改动就是基于Mantle重建(新建)了Model层。这里不正确Mantle作很多其它介绍。仅仅分享一下使用Mantle的决策及运行过程。

    我们遇到的问题

    唱吧是一款上线2年多的App,产品形态的演进和迭代很快。

    因此不可避免的遗留了各种问题:

    • Model层不健全。没有统一的结构。不同project师做法差异非常大;多数是哑类型。且没有统一的序列化机制
    • 业务逻辑冗余、分散、不一致
    • 模块划分任意,依赖关系混乱,维护困难
    • NSDictionary作为承载业务的数据类型在各处出现(sqlite, Model object, API, Notification, web, OpenURL etc.)。參数和值的正确性全然没有编译器检查,字符串非常easy写错,风险延后至执行时,易产生低级bug
    • 基本没有文档和凝视(结合上一点,不挂debugger非常难读懂代码)
    • 几百个API,业务复杂。变动快,重构难;同一个API请求可能有反复和不一致
    • API的一些參数和返回值,同一个參数/返回值可能存在类型差异;因为API须要向前兼容,改动API有成本

    除此之外,还有其它project上的约束:

    • 不能影响现有的API。全部的事情仅仅限于iOS端的改动
    • 代码即文档,由于没有精力维护文档
    • 对不同Model的持久化方式作迁移
    • 避免写大段枯燥的Model的序列化/反序列化代码
    • 没有时间造出足够成熟、健壮可重用的组件及撰写文档

    上述的问题都是长期存在且须要解决的。否则严重影响开发效率及代码质量。

    11年的时候我还在做社交游戏的时候,设计并实现了一套简单的基于Objective-C Runtime的数值表Model结构及转换工具(Model<=>csv)供数值策划使用。但想写出一套成熟的方案还是有一些距离,并且也没有资源和时间作维护、測试和文档。

    顺着这个思路找到了JSONModelMantle,前者刚刚1.0。后者在Github for Mac中广泛使用且社区更成熟(甚至Slack上有channel),所以成为了更好的选择。

    事实也证明这个选择是对的,6.0上线后。crash率比之前的版本号有显示的减少。而且Mantle相关的crash占总crash的比率不到3%,大能够直接用在大型的产品上。

    除了成熟稳定。Mantle基本攻克了我们遇到了的全部问题。

    以下详细介绍一些通用性Mantle使用经验。主要的用法请直接移步Mantle的README


    Property名称转换

    因为API使用的开发语言与iOS所使用的Objective-C是截然不同的,所以可能将一些保留keyword作为property的名称(如id),或者不小心override掉基类的属性(如description)。还有可能API中使用了一个非常糟糕的名称,或者使用了不符合Objective-C命名规范的名称,这些我们都须要作转换。

    仅仅须要实现MTLJSONSerializing protocol并在+JSONKeyPathsByPropertyKey方法中定义好新旧名称的映射关系就可以。Mantle会在序列化及反序列化时对属性名进行自己主动的转换。


    + (NSDictionary *)JSONKeyPathsByPropertyKey {
    return @{
    @"identifier": @"id",
    @"displayDiscription": @"description",
    @"thisIsANewShit": @"newShit",
    @"creativeProduct": @"copyToChina",
    @"betterPropertyName": @"m_wired_propertyName"
    }
    }

    好了非常多吧?没错,仅仅须要定义一次名称的映射关系就能够了,Mantle负责model与JSON之间的双向转换。不须要将这样的逻辑写得到处都是,而且还得维护它的一致性。

    Property的类型映射

    iOS中处理URL使用的是NSURL类型,但JSON仅仅支持主要的字符串。Mantle能够自己主动帮你转换成NSURL。


    + (NSValueTransformer *)URLJSONTransformer {
    return [NSValueTransformer valueTransformerForName:MTLURLValueTransformerName];
    }
    NSValueTransformer负责在不同类型间进行双向转换。请读者研究一下Mantle的实现方式。在此前提下,留给读者一个问题(事实上这是一个真实的故事。类似的故事还有非常多,详见iOS应用开发之十大坑队友):

            

     如果我们有一个entity,名字且叫KTVConcreteEntity吧。它有一个属性名字叫entityID,类型是NSInteger。问题来了。entityID可能在另外一个API的response中是字符串类型,在不直接改动Mantle的源代码的前提下怎么搞?欢迎在下方留言讨论。


    空标量异常

    有的时候API的response会有空值,比方copyToChina可能不是每次都有的,JSON是这样儿的:

    {
    "copyToChina": null
    }

    Mantle在这样的情况会将newShit转换为nil,但假设是标量如NSInteger怎么办?KVC会直接raise NSInvalidArgumentException

    Mantle是基于KVC给property赋值的,KVC提供了- (void)setNilValueForKey:(NSString *)key方法,让我们为nil指定一个合理的替代值。我们来看一下此方法的解释:

    Invoked by setValue:forKey: when it’s given a nil value for a scalar value (such as an int or float).
    Subclasses can override this method to handle the request in some other way, such as by substituting 0 or a sentinel value for nil and invoking setValue:forKey: again or setting the variable directly. The default implementation raises an NSInvalidArgumentException.

    对于标量来讲。多数情况下合理的值即为0,我们来看下代码:

    @interface MTLModel (KTVNullableScalar)
    @end
    @implementation MTLModel (KTVNullableScalar)
    - (void)setNilValueForKey:(NSString *)key {
    [self setValue:@0 forKey:key]; // For NSInteger/CGFloat/BOOL
    }
    @end


    问题完美解决,再也不须要到处写无聊的if/else了。


    其他重要特性

    Mantle为我们带来的方便不胜枚举:

    • 实现了NSCopying protocol,子类能够直接copy是多么爽的事情
    • 实现了NSCoding protocol,跟NSUserDefaults说拜拜
    • 提供了-isEqual:-hash的默认实现,model作NSDictionary的key方便了很多
    • 简单且把一件事情做好。不掺杂网络相关的操作

    如此强大优雅的设计。让我不得不向Github的project师们致敬!


    写在后面

    篇幅所限,仅仅介绍了几个典型的问题。欢迎大家讨论。

    但假设你的App的代码规模仅仅有几万行,或者API仅仅有十几个,或者没有遇到我们这些遗留问题,我建议还是不要引入了,杀鸡用指甲刀就够了。杀不动多磨磨找准要害。

    Anyway。Mantle的实现和思路是值得每位iOSproject师学习和借鉴的。


    原文链接





  • 相关阅读:
    Using Resource File on DotNet
    C++/CLI VS CSharp
    JIT VS NGen
    [Tip: disable vc intellisense]VS2008 VC Intelisense issue
    UVa 10891 Game of Sum(经典博弈区间DP)
    UVa 10723 Cyborg Genes(LCS变种)
    UVa 607 Scheduling Lectures(简单DP)
    UVa 10401 Injured Queen Problem(简单DP)
    UVa 10313 Pay the Price(类似数字分解DP)
    UVa 10635 Prince and Princess(LCS N*logN)
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4906135.html
Copyright © 2020-2023  润新知