近来的

mt=8" target="_blank" rel="external">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师学习和借鉴的。

原文链接

为什么唱iOS 6.0选择Mantle的更多相关文章

  1. embedded dylibs/frameworks are only supported on iOS 8.0 and later 错误解决

    ld: warning: embedded dylibs/frameworks only run on iOS 8 or later ld: embedded dylibs/frameworks ar ...

  2. 在 iOS 10.0 之后, App 要调用手机相机与相簿应注意的事项

    iOS 的 SDK 每一年至少都会有一次大改版,从 2009 到 2016 年,版号已经到了第 10 版了,很轻易的就追上了 Mac OSX. 每一次的大改版都会有不少新的功能或新的规范,在 iOS ...

  3. iOS 从0到1搭建高可用App框架

    iOS 从0到1搭建高可用App框架 最近在搭建新项目的iOS框架,一直在思考如何才能搭建出高可用App框架,能否避免后期因为代码质量问题的重构.以前接手过许多“烂代码”,架构松散,底层混乱,缺少规范 ...

  4. Xcode 9.0 报错, Safe Area Layout Guide Before IOS 9.0

    Xcode 9.0 新建工程报错 xcode Safe Area Layout Guide Before IOS 9.0 如下图,在Builds for 选择iOS9.0 and Later,不勾选U ...

  5. iOS 9.0中UIAlertController的用法。

    1.我为什么要写这篇博客记录它? 答:因为 UIAlertView和UIActionSheet 被划线了 苹果不推荐我们使用这两个类了,也不再进行维护和更新,为了以后方便使用我来记录一下.如图所示 正 ...

  6. iOS 15 无法弹出授权弹框之解决方案---Your app uses the AppTrackingTransparency framework, but we are unable to locate the App Tracking Transparency permission request when reviewed on iOS 15.0

    2021年9月30日下午:我正愉快的期盼着即将到来的国庆假期,时不时刷新下appstoreconnect的网址,28号就提上去的包,今天还在审核中....由于这个版本刚升级的xcode系统和新出的iO ...

  7. HierarchyViewer for iOS 2.0 BETA Introduction

    We know HierarchyViewer is an useful tool in Android SDK. The developer and tester, who haven't the ...

  8. iOS 10.0 更新点(开发者视角)

    html, body {overflow-x: initial !important;}html { font-size: 14px; } body { margin: 0px; padding: 0 ...

  9. iOS 7.0获取iphone UDID 【转】

    iOS 7.0 iOS 7中苹果再一次无情的封杀mac地址,使用之前的方法获取到的mac地址全部都变成了02:00:00:00:00:00.有问题总的解决啊,于是四处查资料,终于有了思路是否可以使用K ...

随机推荐

  1. 双向链表(自己写的c++类)

    UVA还是上不去T T哭瞎了. 只好老老实实的研究上回买的书了. 写得有点长.好吧,我只是来复习C++类的. 特意用class 而不用struct写链表. 数据结构还没学...双向链表就当先预习了. ...

  2. python3 pygame 坦克自动移动

    让坦克自动跑起来 这里需要一个坦克的图. 放到与脚本同一目录. 好,我们就让这个坦克自动跑. 下面上代码: # !/usr/bin/env python # -*- coding:utf-8 -*- ...

  3. git各种命令 & git merge和git rebase的区别

    git merge 和 rebase的区别: http://blog.csdn.net/jollyjumper/article/details/24743751 对于两个分支而言,rebase和mer ...

  4. Android layer-list的属性和使用具体解释

    Android layer-list的属性和使用具体解释.layer-list是用来多个图层堆叠显示的,借这个特性能够做一些特别的效果(比方:阴影.以下的效果等),也能够投机取巧. 1.代码片 < ...

  5. Android(Lollipop/5.0) Material Design(四) 创建列表和卡片

    Material Design系列 Android(Lollipop/5.0)Material Design(一) 简单介绍 Android(Lollipop/5.0)Material Design( ...

  6. HTML/CSS 选择符优先级

    CSS的选择符优先级 1.同级样式默认后者覆盖前者 2.样式优先级 类型(1) < class[type](10)=伪类(10) < id(100) < style行间样式(1000 ...

  7. Kinect for Xbox one(v2) + Ubuntu 14.04 +ROS 安装

    相比于kinect for xbox 360(v1)通过结构光来获取深度,Kinect for Xbox one(v2) 采用time flight技术,极大改善了深度图像的性能. kinect fo ...

  8. 删除GitHub上项目中的某个文件

    原文地址 https://www.jianshu.com/p/242412b43ca5 1.首先在本地中更新有该项目的最新包 即确保本地项目和git上的项目内容保持同步(git pull拉取项目代码) ...

  9. HTTP请求头与响应头

    http://m.blog.csdn.net/article/details?id=48918857 本篇文章中,将学习一下HTTP请求头与响应头的知识. 一.HTTP头引入: 正确的设置HTTP头部 ...

  10. Java内部抛出异常外部不能catch问题分析

    今天在论坛看到一篇关于异常处理的文章,异常处理机制详解开头就搬出了这样一个例子: public class TestException { public TestException() { } boo ...