近来的

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. win8.1 “服务器运行失败”的解决方法

    平台:win8.1 SP1 问题:安装QQ安全管家又卸载后出现了奇怪的问题,1.在桌面点右键→个性化时,提示“服务器运行失败”.2.右键点击“这台电脑”,选择“属性”时没有反应.3.开始屏幕里随便选择 ...

  2. 关于idea新建子目录时往父目录名字后叠加而不是树形结构的解决方法(转)

    我们在IDEA中创建子目录时,子目录总是在父目录后面叠加而不是树形,如下 我们可以打开项目窗口的右上角的设置标志, 将红圈选项的√先去掉,创建好子目录后再将它选中就可以

  3. [WPF自定义控件库]排序、筛选以及高亮

    1. 如何让列表的内容更容易查找 假设有这么一个列表(数据源在本地),由于内容太多,要查找到其中某个想要的数据会比较困难.要优化这个列表,无非就是排序.筛选和高亮. 改造过的结果如上. 2. 排序 在 ...

  4. 用FATFS在SD卡里写一串数字

    用FATFS写SD卡,如写入数组 s[] ={1,2,3,4,5,6} 想要在txt中显示“123456” 就要把 s[0]=1+'0'    或 s[0]=1+48   或 s[0]=1+0x30  ...

  5. AIR 初步 Javascript学习之cookie操作

    //设置cookie的名称,值,过期时间         function setCookie(cookieName,cookieValue,cookieExpire) {             v ...

  6. arcengine,深入理解游标Cursors,实现数据的快速查找,插入,删除,更新

    风过无痕 原文  arcengine,深入理解游标Cursors,实现数据的快速查找,插入,删除,更新 深入理解游标Cursors,实现数据的快速查找,插入,删除,更新 1.查找数据Search Cu ...

  7. IfSpeed 带宽计算

    http://www.360doc.com/content/11/0304/22/2614615_98214710.shtml http://www.cisco.com/support/zh/477/ ...

  8. JavaScript、Ajax与jQuery的关系 分类: C1_HTML/JS/JQUERY 2014-07-31 10:15 3388人阅读 评论(0) 收藏

    简单总结: 1.JS是一门前端语言. 2.Ajax是一门技术,它提供了异步更新的机制,使用客户端与服务器间交换数据而非整个页面文档,实现页面的局部更新. 3.jQuery是一个框架,它对JS进行了封装 ...

  9. 【Lucene4.8教程之三】搜索 2014-06-21 09:53 1532人阅读 评论(0) 收藏

    1.关键类 Lucene的搜索过程中涉及的主要类有以下几个: (1)IndexSearcher:执行search()方法的类 (2)IndexReader:对索引文件进行读操作,并为IndexSear ...

  10. Android 为开发者准备的最佳 Android 函数库(2016 年版)

    本文是翻译自 CloudRAIL 的官方博客(https://cloudrail.com/best-android-libraries-for-developers/),本文中分享的 Android ...