iOS 应用架构谈 本地持久化方案.docx

上传人:b****1 文档编号:2481039 上传时间:2022-10-30 格式:DOCX 页数:22 大小:37.61KB
下载 相关 举报
iOS 应用架构谈 本地持久化方案.docx_第1页
第1页 / 共22页
iOS 应用架构谈 本地持久化方案.docx_第2页
第2页 / 共22页
iOS 应用架构谈 本地持久化方案.docx_第3页
第3页 / 共22页
iOS 应用架构谈 本地持久化方案.docx_第4页
第4页 / 共22页
iOS 应用架构谈 本地持久化方案.docx_第5页
第5页 / 共22页
点击查看更多>>
下载资源
资源描述

iOS 应用架构谈 本地持久化方案.docx

《iOS 应用架构谈 本地持久化方案.docx》由会员分享,可在线阅读,更多相关《iOS 应用架构谈 本地持久化方案.docx(22页珍藏版)》请在冰豆网上搜索。

iOS 应用架构谈 本地持久化方案.docx

iOS应用架构谈本地持久化方案

iOS应用架构谈本地持久化方案

前言

嗯,你们要的大招。

跟着这篇文章一起也发布了CTPersistance和CTJSBridge这两个库,希望大家在实际使用的时候如果遇到问题,就给我提issue或者PR或者评论区。

每一个issue和PR以及评论我都会回复的。

持久化方案不管是服务端还是客户端,都是一个非常值得讨论的话题。

尤其是在服务端,持久化方案的优劣往往都会在一定程度上影响到产品的性能。

然而在客户端,只有为数不多的业务需求会涉及持久化方案,而且在大多数情况下,持久化方案对性能的要求并不是特别苛刻。

所以我在移动端这边做持久化方案设计的时候,考虑更多的是方案的可维护和可拓展,然后在此基础上才是性能调优。

这篇文章中,性能调优不会单独开一节来讲,而会穿插在各个小节中,大家有心的话可以重点看一下。

持久化方案对整个App架构的影响和网络层方案对整个架构的影响类似,一般都是导致整个项目耦合度高的罪魁祸首。

而我也是一如既往的去Model化的实践者,在持久层去Model化的过程中,我引入了VirtualRecord的设计,这个在文中也会详细描述。

这篇文章主要讲以下几点:

根据需求决定持久化方案

持久层与业务层之间的隔离

持久层与业务层的交互方式

数据迁移方案

数据同步方案

另外,针对数据库存储这一块,我写了一个CTPersistance,这个库目前能够完成大部分的持久层需求,同时也是我的VirtualRecord这种设计思路的一个样例。

这个库可以直接被cocoapods引入,希望大家使用的时候,能够多给我提issue。

这里是CTPersistanceClassReference。

根据需求决定持久化方案

在有需要持久化需求的时候,我们有非常多的方案可供选择:

NSUserDefault、KeyChain、File,以及基于数据库的无数子方案。

因此,当有需要持久化的需求的时候,我们首先考虑的是应该采用什么手段去进行持久化。

NSUserDefault

一般来说,小规模数据,弱业务相关数据,都可以放到NSUserDefault里面,内容比较多的数据,强业务相关的数据就不太适合NSUserDefault了。

另外我想吐槽的是,天猫这个App其实是没有一个经过设计的数据持久层的。

然后天猫里面的持久化方案就很混乱,我就见到过有些业务线会把大部分业务数据都塞到NSUserDefault里面去,当时看代码的时候我特么就直接跪了。

问起来为什么这么做?

结果说因为写起来方便~你妹。

keychain

Keychain是苹果提供的带有可逆加密的存储机制,普遍用在各种存密码的需求上。

另外,由于App卸载只要系统不重装,Keychain中的数据依旧能够得到保留,以及可被iCloud同步的特性,大家都会在这里存储用户唯一标识串。

所以有需要加密、需要存iCloud的敏感小数据,一般都会放在Keychain。

文件存储

文件存储包括了Plist、archive、Stream等方式,一般结构化的数据或者需要方便查询的数据,都会以Plist的方式去持久化。

Archive方式适合存储平时不太经常使用但很大量的数据,或者读取之后希望直接对象化的数据,因为Archive会将对象及其对象关系序列化,以至于读取数据的时候需要Decode很花时间,Decode的过程可以是解压,也可以是对象化,这个可以根据具体中的实现来决定。

Stream就是一般的文件存储了,一般用来存存图片啊啥的,适用于比较经常使用,然而数据量又不算非常大的那种。

数据库存储

数据库存储的话,花样就比较多了。

苹果自带了一个CoreData,当然业界也有无数替代方案可选,不过真正用在iOS领域的除了CoreData外,就是FMDB比较多了。

数据库方案主要是为了便于增删改查,当数据有状态和类别的时候最好还是采用数据库方案比较好,而且尤其是当这些状态和类别都是强业务相关的时候,就更加要采用数据库方案了。

因为你不可能通过文件系统遍历文件去甄别你需要获取的属于某个状态或类别的数据,这么做成本就太大了。

当然,特别大量的数据也不适合直接存储数据库,比如图片或者文章这样的数据,一般来说,都是数据库存一个文件名,然后这个文件名指向的是某个图片或者文章的文件。

如果真的要做全文索引这种需求,建议最好还是挂个API丢到服务端去做。

总的说一下

NSUserDefault、Keychain、File这些持久化方案都非常简单基础,分清楚什么时候用什么就可以了,不要像天猫那样乱写就好。

而且在这之上并不会有更复杂的衍生需求,如果真的要针对它们写文章,无非就是写怎么储存怎么读取,这个大家随便Google一下就有了,我就不浪费笔墨了。

由于大多数衍生复杂需求都是通过采用基于数据库的持久化方案去满足,所以这篇文章的重点就数据库相关的架构方案设计和实现。

如果文章中有哪些问题我没有写到的,大家可以在评论区提问,我会一一解答或者直接把遗漏的内容补充在文章中。

持久层实现时要注意的隔离

在设计持久层架构的时候,我们要关注以下几个方面的隔离:

持久层与业务层的隔离

数据库读写隔离

多线程控制导致的隔离

数据表达和数据操作的隔离

1.持久层与业务层的隔离

关于Model

在具体讲持久层下数据的处理之前,我觉得需要针对这个问题做一个完整的分析。

在View层设计中我分别提到了胖Model和瘦Model的设计思路,而且告诉大家我更加倾向于胖Model的设计思路。

在网络层设计里面我使用了去Model化的思路设计了APIMananger与业务层的数据交互。

这两个看似矛盾的关于Model的设计思路在我接下来要提出的持久层方案中其实是并不矛盾,而且是相互配合的。

在网络层设计这篇文章中,我对去Model化只给出了思路和做法,相关的解释并不多,是因为要解释这个问题涉及面会比较广,写的时候并不认为在那篇文章里做解释是最好的时机。

由于持久层在这里胖Model和去Model化都会涉及,所以我觉得在讲持久层的时候解释这个话题会比较好。

我在跟别的各种领域的架构师交流的时候,发现大家都会或多或少地混用Model和ModelLayer的概念,然后往往导致大家讨论的问题最后都不在一个点上,说Model的时候他跟你说ModelLayer,那好吧,我就跟你说ModelLayer,结果他又在说Model,于是问题就讨论不下去了。

我觉得作为架构师,如果不分清楚这两个概念,肯定是会对你设计的架构的质量有很大影响的。

如果把Model说成DataModel,然后跟ModelLayer放在一起,这样就能够很容易区分概念了。

DataModel

DataModel这个术语针对的问题领域是业务数据的建模,以及代码中这一数据模型的表征方式。

两者相辅相承:

因为业务数据的建模方案以及业务本身特点,而最终决定了数据的表征方式。

同样操作一批数据,你的数据建模方案基本都是细化业务问题之后,抽象得出一个逻辑上的实体。

在实现这个业务时,你可以选择不同的表征方式来表征这个逻辑上的实体,比如字节流(TCP包等),字符串流(JSON、XML等),对象流。

对象流又分通用数据对象(NSDictionary等),业务数据对象(HomeCellModel等)。

前面已经遍历了所有的DataModel的形式。

在习惯上,当我们讨论Model化时,都是单指对象流中的业务数据对象这一种。

然而去Model化就是指:

更多地使用通用数据对象去表征数据,业务数据对象不会在设计时被优先考虑的一种设计倾向。

这里的通用数据对象可以在某种程度上理解为范型。

ModelLayer

ModelLayer描述的问题领域是如何对数据进行增删改查(CURD,CreateUpdateReadDelete),和相关业务处理。

一般来说如果在ModelLayer中采用瘦Model的设计思路的话,就差不多到CURD为止了。

胖Model还会关心如何为需要数据的上层提供除了增删改查以外的服务,并为他们提供相应的解决方案。

例如缓存、数据同步、弱业务处理等。

我的倾向

我更加倾向于去Model化的设计,在网络层我设计了reformer来实现去Model化。

在持久层,我设计了VirtualRecord来实现去Model化。

因为具体的Model是一种很容易引入耦合的做法,在尽可能弱化Model概念的同时,就能够为引入业务和对接业务提供充分的空间。

同时,也能通过去Model的设计达到区分强弱业务的目的,这在将来的代码迁移和维护中,是至关重要的。

很多设计不好的架构,就在于架构师并没有认识到区分强弱业务的重要性,所以就导致架构腐化的速度很快,越来越难维护。

所以说回来,持久层与业务层之间的隔离,是通过强弱业务的隔离达到的。

而VirtualRecord正是因为这种去Model化的设计,从而达到了强弱业务的隔离,进而做到持久层与业务层之间既隔离同时又能交互的平衡。

具体VirtualRecord是什么样的设计,我在后面会给大家分析。

2.数据库读写隔离

在网站的架构中,对数据库进行读写分离主要是为了提高响应速度。

在iOS应用架构中,对持久层进行读写隔离的设计主要是为了提高代码的可维护性。

这也是两个领域要求架构师在设计架构时要求侧重点不同的一个方面。

在这里我们所谓的读写隔离并不是指将数据的读操作和写操作做隔离。

而是以某一条界限为准,在这个界限以外的所有数据模型,都是不可写不可修改,或者修改属性的行为不影响数据库中的数据。

在这个界限以内的数据是可写可修改的。

一般来说我们在设计时划分的这个界限会和持久层与业务层之间的界限保持一致,也就是业务层从持久层拿到数据之后,都不可写不可修改,或业务层针对这一数据模型的写操作、修改操作都对数据库文件中的内容不产生作用。

只有持久层中的操作才能够对数据库文件中的内容产生作用。

在苹果官方提供的持久层方案CoreData的架构设计中,并没有针对读写作出隔离,数据的结果都是以NSManagedObject扔出。

所以只要业务工程师稍微一不小心动一下某个属性,NSManagedObjectContext在save的时候就会把这个修改给存进去了。

另外,当我们需要对所有的增删改查操作做AOP的切片时,CoreData技术栈的实现就会非常复杂。

整体上看,我觉得CoreData相对大部分需求而言是过度设计了。

我当时设计安居客聊天模块的持久层时就采用了CoreData,然后为了读写隔离,将所有扔出来的NSManagedObject都转为了普通的对象。

另外,由于聊天记录的业务相当复杂,使用CoreData之后为了完成需求不得不引入很多Hack的手段,这种做法在一定程度上降低了这个持久层的可维护性和提高了接手模块的工程师的学习曲线,这是不太好的。

在天猫客户端,我去的时候天猫这个App就已经属于基本毫无持久层可言了,比较混乱。

只能依靠各个业务线各显神通去解决数据持久化的需求,难以推动统一的持久层方案,这对于项目维护尤其是跨业务项目合作来说,基本就和车祸现场没啥区别。

我现在已经从天猫离职,读者中若是有阿里人想升职想刷存在感拿3.75的,可以考虑给天猫搞个统一的持久层方案。

读写隔离还能够便于加入AOP切点,因为针对数据库的写操作被隔离到一个固定的地方,加AOP时就很容易在正确的地方放入切片。

这个会在讲到数据同步方案时看到应用。

3.多线程导致的隔离

CoreData

CoreData要求在多线程场景下,为异步操作再生成一个NSManagedObjectContext,然后设置它的ConcurrencyType为NSPrivateQueueConcurrencyType,最后把这个Context的parentContext设为Main线程下的Context。

这相比于使用原始的SQLite去做多线程要轻松许多。

只不过要注意的是,如果要传递NSManagedObject的时候,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 人文社科 > 设计艺术

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1