iOS 开发如果涉及数据和表的ios 持久化存储,Core Data 比 SQLite 更好吗

您所在的位置: &
Android和iOS孰优孰劣:真实应用开发过程告诉你答案
Android和iOS孰优孰劣:真实应用开发过程告诉你答案
blog.jobbole
从上面的分析来看,做GQueues的过程中,并没有出现平台A完胜平台B的情况。Android和iOS在某些领域各有千秋,也都有需要改进的地方。
随便搜索一下&Android&vs.&iOS&,都会出现很多关于哪个平台更好的争论,大多数的争论点都是关于市场占有率、易用性和设备分化等问 题。当然也有一些&以开发者的角度&去比较这两个平台的文章,但是很少有从技术上做深入的比较,通常也只是用一个简单的示例应用介绍一些基本的特性。缺少 这种深入的比较其实是有原因的:一个公司要做一个足够复杂的移动应用,通常需要一个人或团队做Android,另外一个人或团队做iOS。这两个平台使用 不同的编程语言(Java和Objective-C),提供不同的SDK,使用不同的开发工具,所以人力资源分配上各做各的平台也就不奇怪了。
GQueues是一个在线任务管理器,之前只有一个HTML5版本。最近我完成了GQueues&for&Android
和GQueues&for&iPhone&&&iPad
的开发。虽然这两个应用的复杂程度不能和第一人称射击游戏相提并论,但也绝不简单&&&为用户存储和管理数以千计的任务信息、支持多账户、提供到WEB端 的后台同步、复杂的过滤、排序和分组功能。通过这次的实践,我希望透过独特的视角,分析和比较为这两个平台开发GQueues应用的过程。
498)this.width=498;' onmousewheel = 'javascript:return big(this)' width="480" height="398" id="pic" alt="" src="/wyfs02/M00/24/83/wKiom1NQxwmSmA2xAAB6HFiaXFk970.jpg" />
Android&App
Sept&21,&2012
Mar&2,&2013
第一个可测的Beta版本
Dec&22,&2012
June&10,&2013
应用发布日期
Jan&31,&2013
July&18,&2013
项目总耗时
4.25&months
4.5&months
Ramp&Up&Time
870&hours&(approx)
960&hours&(approx)
Beta测试&Bugfix
Beta测试人员人数
26,981&lines
23,872&lines
我已经写了12年的代码,但这是我写的第一个Android应用,也是我写的第一个偏向数据处理的iOS应用(2010年我做过两个iOS&3上的 游戏,但那两个游戏主要只涉及一些动画和蓝牙连接)。&我最后一次用Java是在研究生阶段,而我的Objective-C也仅限于那两个游戏。所以对于 这两个平台,我基本上可以算是从零开始。
简单讲,只需要花一半学习iOS的时间来学习Android,我就能开始Android开发。对于Android,我花了一周时间用来看书、跟着一 些教程做一些测试应用,这些测试应用包含了GQueues将会用到的一些核心功能。做完这些,我基本上算是打好了为GQueues设计架构的基础,同时也 可以开始为这个项目写代码了。在接下来的一周我可以很轻松自如地基于Android做开发,而不再需要依赖某个资源去实现新特性了。
对于iOS,我同样按照上面的流程,但我花了两周时间做各种测试/实验,才让自己觉得可以开始为这个项目写一些基础代码了。其中大部分的时间都花在研究CoreData各种复杂的API上面。搞清楚怎么设置、怎么在线程安全的前提下,为每个用户集中管理和也花了些功夫,最重要的是要支持多账户(这个话题可能需要另一篇博客来单独讲讲)。为开发一个可扩展的架构花了更多时间,用于支持可被用户查看以及操作的任务表单、队列和分类。最后又过了两周(总共花了一个月)自己才能比较轻松自如地基于iOS写代码。
总的来说,Android的文档(官方文档、第三方教程、图书、代码示例、StackOverflow)质量都非常高。我从一些著名的开源 Android应用中学到了很多架构上的最佳实践,如Google开放给开发者的2012&Google&I/O&app。此外,Android本身就是 开源的,必要时我可以自己查看Android的平台代码,弄清楚一些疑难问题。虽然iOS也有很多文档,但由于iOS5和iOS6相比之前的版本改动非常 大,大部分文档都已经过时,其中包括ARC入门一文()。因此,大部分的示例代码(包括Apple官方示例)和一些问题的解决方法都是不正确的,需要使用新的方法取而代之。搞清楚这些肯定也需要花更多的时间。
从上面的统计表中也可以看出,开发GQueues&for&Android要比开发 iOS
版的快十分之一的时间,尽管在开发Android版的期间我重新实现了之前用于支持GQueues&HTML5版的整个后端服务器同步代码。而开发一个不 采用原始iOS6风格UI的应用也需要多花些时间,单单比较这个数据,Android开发就是比iOS开发快。
用到的资源
Android App
上面列出来的书其实用处很有限,因为跟大部分的技术类书籍一样,书的内容都有点过时了,而且大部分书只停留在入门级别的概念介绍。不过,在一开始的前几天看一下这些书,能够比较快地理解平台上的一些核心功能。就目前来讲,对于这两个平台,在线资源仍然是最有价值的。
接下来我只简单说一下这两个平台的开发工具,因为关于这个话题已经有很多的讨论。我不是Eclipse或者XCode的脑残粉,它们有各自的强项和 弱点(其实我最喜欢的还是Vim)。Eclipse的搜索暴慢而且很繁琐。XCode&Organizer的文档搜索也卡爆了。Eclipse中使用 log&tags(通过Android插件的logcat集成)过滤日志超级实用。两个IDE的代码补全都很不错,XCode的 Interface&Builder一点用处都没有(后面细讲)。不过XCode&Instruments就非常有用了,可以用它做优化分析、调试等等。 我开始做GQueues&for&Android的时候,Google还没发布Android&Studio,不过在GQueues的后续更新版本中我会 拿它来试试。
如果你一边写代码一边测试,用Android的模拟器简直就是浪费时间(真不敢相信它能慢成这个鸟样)。在开发过程中,我都是直接部署到真机上测试 的,用真机快很多。iOS的模拟器则很不同,跟Android相比简直就是火箭跟蜗牛赛跑,这也让整个开发过程更加高效。每写一小段代码我都会在模拟器上 跑一下,等到整个功能完成了我就会部署到真机上玩玩。
对于Android,我有各个版本的测试机器(除了Gingerbread,即Android&2.3),除此之外,就要倚靠beta测试过程中各种设备的覆盖了。对于iOS来讲就要简单很多了,我只需要拿GQueues需要支持的最旧的和最新的机器来测试就够了。
Android App
Samsung Infuse (Froyo 2.2)
Nexus S (ICS 4.0.3)
Galaxy Nexus (Jelly Bean 4.2)
Samsung Galaxy Tab 10.1 (Honeycomb 3.2)
Nexus 7 (Jelly Bean 4.2)
iPhone 4 (iOS 6)
iPhone 5 (iOS 6)
iPad 2 (iOS 6)
iPad 4th generation (iOS 6)
GQueues的其中一个需求就是必须同时支持任意尺寸的手机和平板,并且针对不同的表单元素进行优化布局。由于各种各样的设备都运行着 Android系统,Android也理所当然地有着成熟的UI组件帮助开发者支持各种尺寸。例如从Android第一个版本开 始,RelativeLayout提供了View之间相对布局的支持,可用于创建灵活、响应迅速的布局。另外,在Android中所有的布局都由XML定 义,这设计界面的方式非常简洁、简单并且高效,试过iOS中创建布局之后这种体会就更加深刻了。
相对于Android的RelativeLayout,iOS有Auto&Layout,这种布局方式比较新(iOS&6新引入的),集成到了 Interface&Builder(IB)中,但是太难用了。我花了好多天学习IB中怎么用Auto&Layout,跟任何iOS&6开发者一样,仅靠 IB为视图(View)设定各种精确的约束,完全改变了我自己的标准,这是因为IB所谓的&智能&系统时刻维持(纠正)着视图布局相对位置。我学了很多技 巧,想着弥补IB的短板,但是没啥作用。最后我只能放弃IB,转而用冗长的代码实现所有布局。如果你放弃IB和富有极客范的 ASCII&art&style来写布局,使用Auto&Layout来实现还是很强大、很直接的。希望苹果在iOS&7中已经改善这些,不过我还木有试 过。
如果一个应用需要同时针对小屏设备和大屏设备进行优化,最关键的就是基于屏幕的真实尺寸进行动态组合视图,这种方式被称作&适配性布局 (Adaptive&Layout)&,平板电脑可以在一屏中显示两个或三个视图,而手机上一屏则只显示一个视图。Android通过Fragments 支持这种设计,Fragment是一个独立的、自包含的的模块,能够在需要的时候直接丢到Activity中去用。通过使用Fragments,只需要调 整几行XML代码就可以让GQueues的布局适配不同分辨率的屏幕。对于我来讲,Fragments是一种非常自然的解决方案,因为它是基于面向对象里 面两个众所周知的准则设计的&-&高内聚和低耦合。
498)this.width=498;' onmousewheel = 'javascript:return big(this)' width="480" height="302" alt="" src="/mw690/7cc829d3gw1ec5ndizmrhj20hv0b80ti.jpg" />
通过Custom&Container&View&Controller(你也可以用Master-Detail模板,当然这种方式宽度是固定的, 也不支持个性化定制),iOS支持一屏使用多个ViewController。对于这个不成熟的特性,我觉得Apple的文档显得很复杂和不完整,最好的 资源还要数Ray&s&iOS5&tutorials和WWDC视频。我花了比预计要多的时间,终于搞好了在iPad上同时显示多个View、在 iPhone上显示单个View的布局架构。
简单说,在Android上支持设备翻转需要做很多工作,这些工作也是最终导致很多bug的源头,而在iOS上,支持屏幕翻转只需要做一点点工作, 剩下就是系统帮我们搞定了。在Android上,屏幕翻转会直接销毁现有整个视图栈(Activity栈),屏幕翻转完成后再重建每个视图。所以在 GQueues中支持屏幕翻转,我需要无时无刻保存好所有当前状态,随时保证翻转后能正常恢复状态。而在iOS上,系统会帮你管理所有屏幕翻转相关的细 节,唯一需要我关心的就是翻转之后,我需要调整那些没有被Auto&Layout处理好的视图的位置。
&复杂&布局
498)this.width=498;' onmousewheel = 'javascript:return big(this)' width="240" height="264" class="alignright" style="color: #333333; font-style:" alt="" src="/wyfs02/M01/24/83/wKiom1NQxwqyym6ZAAA3H5uwciY290.jpg" />
网页开发上有一些常见的布局在GQueues上实现起来非常困难,不管是Android还是iOS。其中一个例子是在任务详细界面显示标签。每个标 签都是变长的,在必要时标签需要自动换行。在网页上实现这个只需要设置CSS的float值就可以了。但不管是Android还是iOS对这种&流式布 局&(Flow&Layout)都没有原生的支持,这也意味着我需要写很多代码自己去计算和摆放这些标签,以达到&流式布局&的效果。最后Android 的代码是基于的演讲内容和的flow&layout实现的。在iOS上也采用了类似的方法,基于容器的总宽度,计算每个标签的宽度,最后设置auto&layout的参数。对于这个布局的实现在两个平台上都耗了很大的工作量。
旧设备支持
关于Android的生态系统常被人吐槽的就是严重的系统分化。运营商推送更新的步伐总是很慢,所以现在仍有大量运行着旧系统的设备,这也就意味着 如果要保证应用足够大的设备覆盖率,开发者就不能使用新版系统带来的新特性。不过好在现在针对这个问题,Android社区做了很大的努力,提供了一些用 于在旧系统上支持新特性的库。通过使用Android官方的&和Jake&Wharton的&Library,我几乎可以在Android&2.2上使用Jelly&Bean(4.2)中所有的新特性。
对于iOS来说,支持旧系统一说几乎不存在,或者说根本就不是关键。在准备阶段我花了一些时间考虑从哪个iOS版本开始支持,而当时的统计数据显示使用iOS&6系统的设备已经达到, 而当时对于放弃支持iPad一代我也有一些疑虑,因为我老爸老妈老姐用的就是iPad一代,他们将是GQueues的铁杆支持者。最后我决定还是只支持 iOS&6+,这样我可以放开手使用Auto&Layout,而不需要浪费大量时间实现任何过时的布局技术。当然,我解决了iPad一代的问题(至少对我 家里人说来说已经解决),就是换掉他们的iPad一代,给他们每人买一个iPad四代(作者有钱银)。
数据存储和管理
对于GQueues来说,数据是核心&-&把数据保存到设备上然后同步到WEB端。Android和iOS有着完全不同的数据管理系统。 Android提供了ContentProvider,它是SQLite数据库上层的一个可被继承的应用接口,作为一个结构化框架被用于所有应用的数据处 理。ContentProvider学习起来比较难,搞定一个GQueues可用的实现,前期需要花很多工作。一旦搞定了第一步后面的扩展和个性化定制都 变得简单多了。
一些背景信息,GQueues的web&service是基于的, 这是一个高扩展性的分布式NoSQL存储系统,而SQLite则是一个标准的关系型数据库,扩展性明显也比较差,但这完全不需要考虑,因为这个应用只存储 一个用户的数据。(顺便说一下,架构上我采用了&一个用户对应一个数据库&的设计,这对于快速简单地实现多用户切换有重要意义,不过实现细节可能得再开一 博来聊了)。不管怎么说,Android的一个很大的优点就是可以创建来支持。为了支持,搞清楚各种复杂的表关联查询和子查询也花了写功夫,但是这也让Smart&Queues的加载更加高效和快速,因为过滤不是在代码里面实现的(在SQL里面)。
498)this.width=498;' onmousewheel = 'javascript:return big(this)' width="320" height="219" class="alignright" alt="" src="/wyfs02/M00/24/83/wKioL1NQxuChoCLMAAAwSOKDdBI366.jpg" />
在iOS上,我用的是, 它是iOS上的&schema驱动数据图形管理和持久化框架&,基本上它可以被看做是一个NoSQL存储,不过有趣的是,Core&Data背后实际上是 SQLite数据库(呃&实际上SQLite也是几个可选项中最合理的选择)。iOS也允许用户直接创建SQLite数据库,但只支持通过纯C代码来操 作,对于其他iOS组件没有原生集成。Core&Data的学习起来也比较困难,但最后我还是选择Core&Data而不用SQLite,因为这样我可以 轻松实现很多功能,包括缓存、数据模型迁移支持,还有通过&NSFetchedResultsController,可以非常简单地为界面中的 table(列表)提供数据。
管理数据集的关键就是使用事务,尤其重要是做数据同步的时候&-&ACID,即:atomic(原子性)、consistent(一致性)、 isolated(隔离性)、durable(持久性)。Android上实现事务似很直观,跟大部分关系型数据库管理系统的实现方式是一样的,因此,保 证数据完整性并不困难。另外,用好SQLite中的UNIQUE&&REPLACE语句,在数据同步的过程中建表、对记录进行原子更新的时候几乎不需要做任何额外工作。
严格来讲,Core&Data并不完全支持事务。通过使用单独的子ManagedObjectContexts做后台线程处理,再加上@synchronized,能够处理好数据更新和同步,同时避免不正确的写操作覆盖(overwrite)。关于,iOS给的建议帮助很小,总的来说,CoreData给我的赶脚很笨重,并没有它声称的那么好用。另外,在Android上,SQLite可以轻松实现快速加载Smart&Queues,而在iOS上,所有的过滤都必须在代码中实现,就算用了大量的缓存,速度仍然很慢。
在GQueues&for&Android上增加强大的全文搜索功能很简单,我模仿Google&I/O应用里面的搜索实现,使用了SQLite的特性。首先创建一个虚拟表,然后在一个存储了用户任务的表上设置几个触发器,由这些触发器填充数据到虚拟表。做完了这些,剩下的就是设计一个搜索界面和为搜索历史添加存储。
iOS的Core&Data对于全文搜索并没有原生支持,所以我通过在谓词(Predicate)中使用LIKE语句,实现基本的任务描述和日记的搜索功能。这个实现当然没有全文搜索那么强大,但我认为它已经能够覆盖现实生活中大部分的使用场景了。
用于比较,我只会列举在GQueues中使用到的几个API。
快速添加(Quick&Add)
正则表达式在实现GQueues中解 析的时候扮演着一个非常重要的角色,幸运的是,Android和iOS对于正则表达式都有着原生的支持。Android中的Pattern和 Matcher从第一个版本起就开始支持,同时也包含了很多正则语法,其中包括前向断言(look-ahead&assertion)和后向断言 (look-behind&assertion)。iOS则从iOS&4开始引入类,令人高兴的是,我可以把我在Android上辛辛苦苦写好的正则表达式几乎原封不动地搬到了iOS上。
498)this.width=498;' onmousewheel = 'javascript:return big(this)' width="179" height="320" class="alignright" alt="" src="/wyfs02/M00/24/83/wKioL1NQxuGxypYhAAAhhSkxa0s777.jpg" />
在设计界面的时候,我希望用户在查看任务详细的时候左右滑动切换。在Android上我用了&和新的类,FragmentStatePagerAdapter 还处于试验阶段,并且只能通过支持库(Support&Library)来使用。我花了几天的时间实现了一个绑定好数据的初级版本,同时解决了几个关于重 复菜单项的bug和在数据发生变化后的处理。这些比我预想的要困难很多,要不是因为左右滑动切换任务的用户体验那么好的话,我真不想实现这个功能。iOS 上的就简单很多了,虽然也有一些奇怪问题要解决,并且需要自己再加上缓存支持使滑动复杂视图的时候达到可用状态。
Android提供了了一个先进但很容易使用的speech-to-text&API,只用20行代码,我就把集成到GQueues,提供了一个。但很遗憾,iOS并没有提供支撑SIRI背后技术的API,开发者只能使用第三方库,依赖键盘上的麦克风提供语音输入的支持。我找了各种第三方库,包括&-&SIRI语音识别的提供商,但发现没有免费版本,收费版本价格不菲。所以最后GQueues只能靠用户自己使用键盘上内置的麦克风选项来进行语音输入,其实这也已经足够了,只要用户还记得有这么个功能。
分享/插件(小部件)
通过使用Intent,在Android上可以很容易就可以把我的应用集成到安装在用户手机上的其他应用。同样地,只需要很少的代码,通过支持&intent,我就能够让用户在其他应用中创建GQueues任务。Android同时也提供了一个小部件平台,于是我也做了几个小部件,以后还会增加一些。iOS对于跨应用集成和桌面小部件的支持度为零,完全不支持这两个功能。
测试和发布
在上面的统计概况表中已经指出,beta版面向真实用户测试了一个多月。两组测试人员都非常棒,帮我找到了数十计的bug,提出了增加一些特性的建 议,对一些UI上不合理的地方提出了反馈。我通过私有的Google&Group组织beta测试,这样的beta测试保证了最后发布的应用对人们是真正 有用的。在每次beta测试的最后,通过调查问卷我收集到了很多有建设性的反馈,也帮助进一步判断我的应用是否达到了可发布的状态。
让测试者开始测试只需要发个APK的链接,让他们下载到他们机器上(呃..他们还需要在设置界面中开启&允许安装Google&Play以外的应用&的选项)。Google很方便地支持用真实用户来进行alpha和beta测试,可在中进行设置。在未来的版本更新中我想用用这两个功能。
iOS中的beta测试困难得多,就算用了服 务,虽然TestFlight很大程度地简化了流程。为了满足Apple的控制欲,每部测试设备的UUID都要加到用于签名beta版应用的证书当中。因 此,每次要添加beta测试者的时候,不论是添加一个人还是一群人,我都需要重新build一遍我的app。除此之外,Apple还限制了你一年最多只能 注册100个测试设备。所以我要小心利用好这100个坑,这也是为什么GQueues的iOS测试者只有Android的一半。
当然,不谈谈发布流程,Android和iOS的比较都不算完,在Google&Play上发布GQueues是一件很好玩的事情,只要我认为已经 准备好了,我随时可以发布我的应用。点下按钮之后,30分钟内,我的应用就能在Google&Play上被全世界的用户找到并安装到他们的设备上。而在 App&Store上发布一款应用,相信每个iOS开发者都有同样的感受,那是一个令人感到郁闷的经历。经过了数月紧张严密的编码,我只能把我的创作提交 给Apple,然后等7天,7天之后审核人员花2分钟看看我的应用,最后拒绝了我的提交。我只能按要求做了修改之后再次提交,我又得等8天才在最后通过了 审核。当然还有很多关于提交应用到App&Store的恐怖故事,跟他们比起来,我就像是公园里逛了一圈。尽管如此,在自己的商业控制上要对这样一个&情 绪化的第三方平台&做出那么多的让步,仍然让我觉得很不爽。
获胜的平台
从上面的分析来看,做GQueues的过程中,并没有出现平台A完胜平台B的情况。Android和iOS在某些领域各有千秋,也都有需要改进的地 方。从这两个平台的历史来看,貌似目前Android势头更猛一些,不止体现在市场占有率上,而是看到了Android近两年在UI上的改进和开发平台的 稳步提升。而Apple则是封闭的王者,我也坚信他们在很努力地做着他们认为是下一代移动计算革命的事情。不管怎么说,当我想想这6年间所兴起的app生 态圈,我为自己在这个移动技术快速更新的时代,能在这两个平台上做开发感到荣幸。【编辑推荐】【责任编辑: TEL:(010)】
关于&&&&的更多文章
《打造高质量Android应用:Android开发必知的50个诀窍》是目前唯
既然强大的Android Studio来了,有什么理由不去用呢?
微软的思路很明确。一个消费者需要拥有几款电子设备?
中秋已过,圆圆的月亮似乎是一个害羞的姑娘,带上了一
对于设计师来说,扁平化设计是一种实打实的设计风格,
Cisco 640-801
Cisco& Certified Network Associate (CCNA&)
Q&A with explanations
Version 93.0
Windows Phone专家
Android开发专家
51CTO旗下网站当前访客身份:游客 [
有笔有梦有肝胆,亦狂亦使亦温文。
:fitColumns:true,会导致在单页数据量超过50条时...
:引用来自“web智能”的评论 引用来自“独-奏”的...
:引用来自“独-奏”的评论 引用来自“web智能”的...
:引用来自“web智能”的评论 不是有六大原则嘛边学...
:不是有六大原则嘛
今日访问:6
昨日访问:18
本周访问:36
本月访问:357
所有访问:9301
iOS数据持久化 -- Core Data
发表于1年前( 19:32)&&
阅读(81)&|&评论()
0人收藏此文章,
Core Data是一个功能强大的层,位于SQLite数据库之上,它避免了SQL的复杂性,能让我们以更自然的方式与数据库进行交互。Core Data将数据库行转换为OC对象(托管对象)来实现,这样无需任何SQL知识就能操作他们。
Core Data位于MVC设计模式中的模型层,一般需要在设备上存储结构化数据时,考虑使用SQLite或是序列化等方法,而Core Data是这两种方法的混合体,并增加了一些功能,提供了SQL强大威力,但是用起来又和序列化一样简单。Core Data能将应用程序中的对象直接保存到数据库中,无需进行复杂的查询,也无需确保对象的属性名和数据库字段名对应,这一切都由Core Data完成。
Core Data的核心——托管对象
托管对象是要存储到数据库中的对象的一种表示,可以看成是SQL记录,它通常包含一些字段,这些字段与应用程序中要存储的对象的属性进行匹配,创建托管对象后,必须将气托管到托管对象上下文中,然后才可以存储到数据库中。
托管对象上下文:
托管对象上下文包含所有的托管对象,这些托管对象已经为提交给数据库准备就绪,在托管对象上下文中,可以添加、修改和删除托管对象,这一层相当于应用程序和数据库之间的缓冲区。
托管对象表:
托管对象表描述了数据库的架构(schema),供托管对象上下文与数据库交互时使用。托管对象表包含一些列实体描述,每个实体都描述了一个数据库表,用于将托管对象映射到数据库条目。
下面来创建一个Core Data
首先要保证引入了CoreData.framwork框架到项目中,然后新建模型文件,New File——Core Data中的Data Model,然后命名为CDJournal.Xcdatamodel,这里我们做一个简单的记录流水账的程序。
接下来是定义数据库实体,选中CDJournal.Xcdatamodel文件打开表编辑器,点击添加一个名为Entry的实体,然后可以为实体添加属性并指定属性的数据类型。还可以创建其他实体,如果一个实体包含另一个实体,可通过拖放建立关系,类似于SQL外键,比如建立一个Author实体可以有多个Entry。建立实体及属性如下图:
创建完实体后必须生成表示数据库对象的类,使我们能在代码中表示实体,选择Entry实体,然后选择菜单Editor——Create NSManagedObject Subclass,点击create,就完成了。完成后可以看到工程中多了一个Entry的h和m文件,这就是Core Data模型中的实体对象。基本准备工作就完成了,如下是工程目录:
现在开始编写初始化Core Data模型的代码
首先,在AppDelegate.h中声明Core Data需要的对象,代码如下:
#import&&UIKit/UIKit.h&&&
//引入CoreData框架&&
#import&&CoreData/CoreData.h&&&
@classViewC&&
@interface&AppDelegate&:&UIResponder&&UIApplicationDelegate]]&&&
@property&(strong,&nonatomic)&UIWindow&*&&
@property&(strong,&nonatomic)&ViewController&*viewC&&
//数据模型对象&&
@property(strong,nonatomic)&NSManagedObjectModel&*managedObjectM&&
//上下文对象&&
@property(strong,nonatomic)&NSManagedObjectContext&*managedObjectC&&
//持久性存储区&&
@property(strong,nonatomic)&NSPersistentStoreCoordinator&*persistentStoreC&&
//初始化Core&Data使用的数据库&&
-(NSPersistentStoreCoordinator&*)persistentStoreC&&
//managedObjectModel的初始化赋值函数&&
-(NSManagedObjectModel&*)managedObjectM&&
//managedObjectContext的初始化赋值函数&&
-(NSManagedObjectContext&*)managedObjectC&&
然后在.m文件中实现定义的方法:
-(NSManagedObjectModel&*)managedObjectModel&&
&&&&if&(managedObjectModel&!=&nil)&{&&
&&&&&&&&returnmanagedObjectM&&
&&&&managedObjectModel&=&[[NSManagedObjectModel&mergedModelFromBundles:nil]&retain];&&
&&&&return&managedObjectM&&
-(NSPersistentStoreCoordinator&*)persistentStoreCoordinator&&
&&&&if&(persistentStoreCoordinator&!=&nil)&{&&
&&&&&&&&returnpersistentStoreC&&
&&&&//得到数据库的路径&&
&&&&NSString&*docs&=&[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,&NSUserDomainMask,&YES)&lastObject];&&
&&&&//CoreData是建立在SQLite之上的,数据库名称需与Xcdatamodel文件同名&&
&&&&NSURL&*storeUrl&=&[NSURL&fileURLWithPath:[docs&stringByAppendingPathComponent:@"CDJournal.sqlite"]];&&
&&&&NSError&*error&=&&&
&&&&persistentStoreCoordinator&=&[[NSPersistentStoreCoordinator&alloc]initWithManagedObjectModel:[self&managedObjectModel]];&&
&&&&if&(![persistentStoreCoordinator&addPersistentStoreWithType:NSSQLiteStoreType&configuration:nil&URL:storeUrl&options:nil&error:&error])&{&&
&&&&&&&&NSLog(@"Error:&%@,%@",error,[error&userInfo]);&&
&&&&returnpersistentStoreC&&
-(NSManagedObjectContext&*)managedObjectContext&&
&&&&if&(managedObjectContext&!=&nil)&{&&
&&&&&&&&return&managedObjectC&&
&&&&NSPersistentStoreCoordinator&*coordinator&=[self&persistentStoreCoordinator];&&
&&&&if&(coordinator&!=&nil)&{&&
&&&&&&&&managedObjectContext&=&[[NSManagedObjectContext&alloc]init];&&
&&&&&&&&[managedObjectContext&setPersistentStoreCoordinator:coordinator];&&
&&&&return&managedObjectC&&
另外,为了保证需要存储的数据不丢失,添加如下代码:
//这个方法定义的是当应用程序退到后台时将执行的方法,按下home键执行(通知中心来调度)&&
//实现此方法的目的是将托管对象上下文存储到数据存储区,防止程序退出时有未保存的数据&&
-&(void)applicationWillTerminate:(UIApplication&*)application&&
&&&&NSError&*&&
&&&&if&(managedObjectContext&!=&nil)&{&&
&&&&&&&&//hasChanges方法是检查是否有未保存的上下文更改,如果有,则执行save方法保存上下文&&
&&&&&&&&if&([managedObjectContext&hasChanges]&&&&![managedObjectContext&save:&error])&{&&
&&&&&&&&&&&&NSLog(@"Error:&%@,%@",error,[error&userInfo]);&&
&&&&&&&&&&&&abort();&&
&&&&&&&&}&&
然后对xib文件进行布局并连接IBOutlet和IBAction
ViewController.h代码如下:
#import&&UIKit/UIKit.h&&&
#import&"AppDelegate.h"&&
@interface&ViewController&:&UIViewController&&
@property&(retain,&nonatomic)&IBOutletUITextField&*titleTextF&&
@property&(retain,&nonatomic)&IBOutletUITextField&*contentTextF&&
@property&(strong,nonatomic)&AppDelegate&*myD&&
@property&(strong,nonatomic)&NSMutableArray&*&&
//单击按钮后执行数据保存操作&&
-&(IBAction)addToDB:(id)&&
//单击按钮后执行查询操作&&
-&(IBAction)queryFromDB:(id)&&
//当通过键盘在UITextField中输入完毕后,点击屏幕空白区域关闭键盘的操作&&
-(IBAction)backgroundTapped:(id)&&
ViewController.m代码如下:
#import&"ViewController.h"&&
#import&"Entry.h"&&
@interfaceViewController&()&&
@implementation&ViewController&&
@synthesize&titleTextF&&
@synthesize&contentTextF&&
@synthesize&myDelegate&=&_myD&&
@synthesize&entries&=&_&&
-&(void)viewDidLoad&&
&&&&[superviewDidLoad];&&
&&&&//获取当前应用程序的委托(UIApplication&sharedApplication为整个应用程序上下文)&&
&&&&self.myDelegate&=&(AppDelegate&*)[[UIApplication&sharedApplication]&delegate];&&
-&(void)viewDidUnload&&
&&&&[selfsetTitleTextField:nil];&&
&&&&[selfsetContentTextField:nil];&&
&&&&[superviewDidUnload];&&
&&&&//&Release&any&retained&subviews&of&the&main&view.&&
-&(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation&&
&&&&return&(interfaceOrientation&!=&UIInterfaceOrientationPortraitUpsideDown);&&
-&(void)dealloc&{&&
&&&&[titleTextFieldrelease];&&
&&&&[contentTextFieldrelease];&&
&&&&[superdealloc];&&
//单击按钮后执行数据保存操作&&
-&(IBAction)addToDB:(id)sender&{&&
&&&&//让CoreData在上下文中创建一个新对象(托管对象)&&
&&&&Entry&*entry&=&(Entry&*)[NSEntityDescription&insertNewObjectForEntityForName:@"Entry"&inManagedObjectContext:self.myDelegate.managedObjectContext];&&
&&&&[entry&setTitle:self.titleTextField.text];&&
&&&&[entry&setBody:self.contentTextField.text];&&
&&&&[entry&setCreationDate:[NSDatedate]];&&
&&&&NSError&*&&
&&&&//托管对象准备好后,调用托管对象上下文的save方法将数据写入数据库&&
&&&&BOOL&isSaveSuccess&=&[self.myDelegate.managedObjectContextsave:&error];&&
&&&&if&(!isSaveSuccess)&{&&
&&&&&&&&NSLog(@"Error:&%@,%@",error,[error&userInfo]);&&
&&&&}else&{&&
&&&&&&&&NSLog(@"Save&successful!");&&
//单击按钮后执行查询操作&&
-&(IBAction)queryFromDB:(id)sender&{&&
&&&&//创建取回数据请求&&
&&&&NSFetchRequest&*request&=&[[NSFetchRequest&alloc]&init];&&
&&&&//设置要检索哪种类型的实体对象&&
&&&&NSEntityDescription&*entity&=&[NSEntityDescription&entityForName:@"Entry"inManagedObjectContext:self.myDelegate.managedObjectContext];&&
&&&&//设置请求实体&&
&&&&[request&setEntity:entity];&&
&&&&//指定对结果的排序方式&&
&&&&NSSortDescriptor&*sortDescriptor&=&[[NSSortDescriptor&alloc]&initWithKey:@"creationDate"ascending:NO];&&
&&&&NSArray&*sortDescriptions&=&[[NSArray&alloc]initWithObjects:sortDescriptor,&nil];&&
&&&&[request&setSortDescriptors:sortDescriptions];&&
&&&&[sortDescriptions&release];&&
&&&&[sortDescriptor&release];&&
&&&&NSError&*error&=&&&
&&&&//执行获取数据请求,返回数组&&
&&&&NSMutableArray&*mutableFetchResult&=&[[self.myDelegate.managedObjectContext&executeFetchRequest:request&error:&error]&mutableCopy];&&
&&&&if&(mutableFetchResult&==&nil)&{&&
&&&&&&&&NSLog(@"Error:&%@,%@",error,[error&userInfo]);&&
&&&&self.entries&=&mutableFetchR&&
&&&&NSLog(@"The&count&of&entry:%i",[self.entriescount]);&&
&&&&for&(Entry&*entry&inself.entries)&{&&
&&&&&&&&NSLog(@"Title:%@---Content:%@---Date:%@",entry.title,entry.body,entry.creationDate);&&
&&&&[mutableFetchResult&release];&&
&&&&[request&release];&&
//更新操作&&
-(void)updateEntry:(Entry&*)entry&&
&&&&[entry&setTitle:self.titleTextField.text];&&
&&&&[entry&setBody:self.contentTextField.text];&&
&&&&[entry&setCreationDate:[NSDatedate]];&&
&&&&NSError&*&&
&&&&BOOL&isUpdateSuccess&=&[self.myDelegate.managedObjectContextsave:&error&];&&
&&&&if&(!isUpdateSuccess)&{&&
&&&&&&&&NSLog(@"Error:%@,%@",error,[error&userInfo]);&&
//删除操作&&
-(void)deleteEntry:(Entry&*)entry&&
&&&&[self.myDelegate.managedObjectContext&deleteObject:entry];&&
&&&&[self.entriesremoveObject:entry];&&
&&&&NSError&*&&
&&&&if&(![self.myDelegate.managedObjectContext&save:&error])&{&&
&&&&&&&&NSLog(@"Error:%@,%@",error,[error&userInfo]);&&
//当通过键盘在UITextField中输入完毕后,点击屏幕空白区域关闭键盘的操作&&
-(IBAction)backgroundTapped:(id)sender&&
&&&&[titleTextField&resignFirstResponder];&&
&&&&[contentTextField&resignFirstResponder];&&
最后运行并填入数据,点击Add后添加成功
多添加几条数据后点击Query便可以查看输出的查询结果,在命令行的输出结果如下:
以上就是对Core Data的一个简单的使用,Core Data还有很多功能,这里就不一一列举,具体的在Apple的官方文档中有详细解释。
1)">1)">1" ng-class="{current:{{currentPage==page}}}" ng-repeat="page in pages"><li class='page' ng-if="(endIndex<li class='page next' ng-if="(currentPage
相关文章阅读

我要回帖

更多关于 ios数据持久化方式 的文章

 

随机推荐