Core Data 教学
看了一篇国外的文章,关于iOS9的Core Data教学,在这里做了一下总结
Core Data 教学
示例开源地址:LastDayCoreData
在这篇文章中我们将学习Core Data的系列教程,你将使用Swift2.0写你的Core Data。你将发现在Xcode中它是很容易上手的,从启动代码导师数据模型编辑器。在教程结束后,你会了解到:
- 使用Xcode的model editor将你想存储在Core Data。
- 添加新的记录到 Core Data
- 从Core Data中读取一组数据
- 在表视图中显示所获取的结果
你也将会了解Core Data背后的数据是什么,以及如何进行交互。OK,现在让我们来构建我的app吧。
开始
打开你的Xcode新建一个iPhone工程,选择Single View Application template起名为HitList并且选择Use Core Data。
选中Use Core Data复选框后将会在AppDelegate.swift生成Core Data stack样本代码
Core Data stack由一组对象组成,方便于检索和保存Core Data的数据。有一个对象最为一个整体来管理Care Data的状态和数据模型等等。
这个示例程序的想法很简单。有一个被叫”hit list”的表视图。你可以在这个列表中添加名字,并且最终你将使用Core Data确保数据在各个环节之间。
点击Main.storyboard在Interface Builder.接下来点击Editor,选择Navigation Controller。具体操作如图所示:
返回Interface Builder,拖拽一个Table view。
接下来拖拽一个Bar Button Item将它放置到navigation bar。最终,起名为Add。就像这样
当你每次点击Add的时候,一个包含文本信息字段的弹框将会出现在屏幕上显示。在那里你能够输入默认的名字到进入文本域。
如果你想知道原因,你可以不设置表示图的委托,这样就不会触发任何行为。
打开Assistant Editor拖拽table view到 ViewController.swift,在类中插入一个outlet:
起名为 tableview
@IBOutlet weak var tableView: UITableView!
同样将Add拖拽到ViewController.swift,创建一个action 命名为addName:
@IBAction func addName(sender: AnyObject) {
}
那么现在你可引用表示图和按钮了。接下来就是建立表示图模型。在ViewContrroller.swift中添加一下代码:
//Insert below the tableView IBOutlet
var names = [String]()
names是一个可变的shtring类型的数组,在tableview中显示。
在viewDidLoad()中实现一下代码:
override func viewDidLoad() {
super.viewDidLoad()
title = "\"The List\""
tableView.registerClass(UITableViewCell.self,
forCellReuseIdentifier: "Cell")
}
在这里将建立一个标题,注册UITableViewCell在table view类中。table view将返回正确类型的cell
仍然在ViewController.swift,添加UITableViewDataSource,UITableViewDelegate
//Add UITableViewDataSource to class declaration
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
//这里添加
tableView.dataSource = self
tableView.delegate = self
}
这个时候Xcode会提示ViewCotroller不符合协议.实现data source方法修改这个错误。
// MARK: UITableViewDataSource
func tableView(tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return names.count
}
func tableView(tableView: UITableView,
cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {
let cell =
tableView.dequeueReusableCellWithIdentifier("Cell")
cell!.textLabel!.text = names[indexPath.row]
return cell!
}
如果你用过UITableView,这段代码看起来会很相似。第一个方法就是names数量。
第二个方法tableView(_:cellForRowAtIndexPath:)返回对cell对象。
不要现在就运行。首先你需要一个输入names的方法然后在table view中进行显示他们。
实现addName IBAction
//Implement the addName IBAction
@IBAction func addName(sender: AnyObject) {
let alert = UIAlertController(title: "New Name",
message: "Add a new name",
preferredStyle: .Alert)
let saveAction = UIAlertAction(title: "Save",
style: .Default,
handler: { (action:UIAlertAction) -> Void in
let textField = alert.textFields!.first
self.names.append(textField!.text!)
self.viewWillAppear(true)
self.tableView.reloadData()
})
let cancelAction = UIAlertAction(title: "Cancel",
style: .Default) { (action: UIAlertAction) -> Void in
}
alert.addTextFieldWithConfigurationHandler {
(textField: UITextField) -> Void in
}
alert.addAction(saveAction)
alert.addAction(cancelAction)
presentViewController(alert,
animated: true,
completion: nil)
}
每次点击Add按钮的时候,这个方法该方法弹出文本域和两个按钮,保存和取消。
点击保存,将其名称插入到数组中,table view将重新加载数据并显示。
在这里,构建并且第一次运行我们的应用程序。点击顶部的Add按钮,将会插入一个弹框。
添加4个或者5个左右的数据,就是下面的样子
你的table view将显示数据,但是并不能实现持久化,什么意思呢?就是说我们现在的数组数据是存放在内存中的,但是如果我们一旦强制退出应用程序或者重新启动你的设备,你的数组数据就会被销毁。
Core Data提供持久化,意思就是他可让数据保持为持久状态,尽管应用重新启动或者是重新运行。
你现在还没有添加任何Core Data。让我们来测试下,切换到Simulator,点击Shift+⌘+H,将会返回home界面。
看到HitList图标,点击它切换到应用,这些名字一样存在着。这跟我们刚才描述的不一样,为什么呢?
当你点击Home按钮的时候。这个时候操作系统会瞬间冻结所有当前在内存中的一切信息。包括我们的名称数组字符串。同样,当我们的应用切换回去的时候,操作系统会恢复过去的记忆,就像你从来没有离开过一样,意思就是我们的names被恢复了。
多任务模式早在iOS 4中推出。他们创造了iOS用户无缝体验,同时也添加了持续性的概念,这心真的存在吗?
不,这不是真的。如果你完全杀死应用程序或者关闭你的iPhone,你的names数组就会消失。你可以体验下,快速的双击Home。
在这里,向上拉动你的应程序,在这里就会将程序杀死了。这个时候反回Home,再一次点击你的应用程序,names就会消失。
以上展现的两种方式书有差异的,所以这里看来了解熟悉多任务模式是显而易见的。但是这个在用户的头脑中是没有什么区别的。用户不会在乎通过哪种方式切回到Home,或者切回到应用。
现在的问题就是怎么样让应用无论通过哪种方式返回都能够存在。
现在就到了我们要讲诉的东西了,实现真正的持久性,数据在一个应用中无论怎样都会存在着。
数据建模
现在你知道如何检测持久性了,让我们开始Core Data的学习。你的目标很简单,就是持久化你输入的名字,重新启动后仍然存在这个应用程序中。
这这里,你已经了解了如何在内存中存储names名称。在这里你将使用Core Data代替那种方法。
第一步就是创建一个managed object model,就是意味着通过Core Data数据将在磁盘上。默认情况下,Core Data使用SQlite数据库作为持久化的存储,所以你可以想象数据模型看成数据库架构。
当你创建了工程的时候我们选择了Use Core Data,Xcode会自动创建一个数据模型文件叫做HitList.xcdatamodeld
点击HitList.xcdatamodeld打开它,正如你所看到的,Xcode有自己的数据模型编辑器,就像如图所示那样
这个数据模型有很多功能,让我们创建一个简单的数据实体。
在左下方点击 Add Entity创建一个新的实体,双击我们新创建的实体,并且改名为Person,就像这样:
你可能很想知道为什么数据模型编辑器使用”实体”,而不是简单的定义一个新类。你不久就会看到,Core Data的数据来源于自身的词汇表。以下有一些常见的书语你可能会遇到:
- 在Core Data中一个entity是一个类的定义。举一个典型的例子就是员工和公司的例子。在关系型数据库中,一个实体对应一个表。
- 一个attribute是连接到特定实体信息的一部分。例如,一个员工可以拥有姓名,职位,工资等attribute。在数据库中attribute(属性)对应表中特定的字段。
- relationship是多个实体之间的一个连接。
现在你知道了什么是attribute,返回模型编辑并且添加一个attribute到Person中,选择Person,点击+。
建立一个name并且选择类型为String。
在Core Data包含很多种数据类型,String是其中的一种。
保存数据到Core Data
在ViewCortroller.swift中 Import Core Data
//Add below "import UIKit"
import CoreData
在Objective-C你可能不得不手动链接框架,但是在Swift中,一个简单的Import语句就就可以让你在你的代码中使用API。
接下来,更换模型。
//将names变味people,并且将people类型改为NSManagedObject类型
var people = [NSManagedObject]()
接下来你存储的是Person实体而不是names,所以将数据模型更名为people,并且它现在是NSManagedObject类型而不是简单的String类型。
NSManagedObject被称为在Core Data中的单一对象。你必须使用它创建,修改,保存和删除操作你的持久数据。
就在刚刚你已经改变了视图的模型,你必须也要使用下面的代码替换原来的数据源。
//Replace both UITableViewDataSource methods
func tableView(tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return people.count
}
func tableView(tableView: UITableView,
cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {
let cell =
tableView.dequeueReusableCellWithIdentifier("Cell")
let person = people[indexPath.row]
cell!.textLabel!.text =
person.valueForKey("name") as? String
return cell!
}
其实通过比较来看其实最显著的变化在cellForRowAtIndexPath,仔细看看就能够发现其中的变化。
当然,你需要注意的地方还有就是你是如何从NSManagedObject抓去name属性。
cell!.textLabel!.text = person.valueForKey("name") as? String
为什么用以上的方式呢?因为NSManagedObject并不知道在你的数据模型中name是如何被定义在你的数据模型中的,因此没有办法直接访问你的name属性。唯一的方法就是用过Core Data提供的key-value来读取,这种方式通常被叫做KVC。
我在这里同样也简单的介绍一下KVC吧。就是说如果你是一个新的iOS开发者可能不了解什么是KVC或者是key-vale编码。KVC就是Cocoa和Cocoa Touch的机制来访问一个对象的而属性间接的使用字符串来识别。在以上的情况下,KVC就像是一本字典。
接下来就是改变我们@IBAction addName方法:
let saveAction = UIAlertAction(title: "Save",
style: .Default,
handler: { (action:UIAlertAction) -> Void in
let textField = alert.textFields!.first
self.saveName(textField!.text!)
self.tableView.reloadData()
})
看到上面我们有新添加了一个saveName方法
func saveName(name: String) {
//1
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
//2
let entity = NSEntityDescription.entityForName("Person",
inManagedObjectContext:managedContext)
let person = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext: managedContext)
//3
person.setValue(name, forKey: "name")
//4
do {
try managedContext.save()
//5
people.append(person)
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
这里面都是什么呢?我们来分析下
- 在你做svae操作之前,你需要先获取NSManagedObjectContext。你可以认为这是用来managed object context的。想进行保存对象到Core Data中需要两步,首先,你需要插入一个对象到managed object context中。然后提交,将该对象存储到磁盘中。Xcode其实已经产生一个通用的模板,当你选择Use Core Data的时候。这个默认的managed object context存在于application delegate中。要想引用它,你需要获取一个app delegate引用。
- 创建managed object context并且完成NSManagedObject的初始化,init(entity:insertIntoManagedObjectContext:).你可能会想到NSEntityDescription的所有相关东西
- 使用NSManagedObject,必须使用你建立的name,必须使用KVC,否则会出现崩溃现象。
- 你的提交的person被保存在磁盘中,注意save会抛出异常,这就是为什么我们需要使用try do。
- 接下来就要恭喜你已经成功并且安全的的实现了数据的持久化。仍然是当我们插入后将会重新加载视图
这比使用一个字符串可能复杂的很多,但是并不是很复杂。这里的代码就是获取managed object context和entity,
构建并且运行,添加一些类似下面的名字。
如果你的数据已经在Core Data中存储,并且实现了数据的持久化,这个时候我们杀死我们的app,然后重现加载我们程序,等一下,发生了什么?table view是空的
你存续到Core Data中的数据但是重新加载后并没有,仍然是空的,其实数据事实上在那里的等待着,你并没有显示它、
从Core Data中获取
要得到持久化的数据,你必须取出它。在ViewController.swift中天添加一个方法
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//1
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
//2
let fetchRequest = NSFetchRequest(entityName: "Person")
//3
do {
let results =
try managedContext.executeFetchRequest(fetchRequest)
people = results as! [NSManagedObject]
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
以上代码中做了什么?
- 就像刚才说的,在做一些操作前你需要获取一个managed object context。从delegate中引用managed object context.
- 根据名字就能看出来,NSFetchRequest就是返回的数据。
- executefetchrequest()返回满足managed objects读取请求中指定的标准数组。
构建并且重新运行,就能发现你想要的效果了
现在你就可以随意的测试了。
Core Data 教学的更多相关文章
- iOS之Core Data及其线程安全
一.简介 Core Data是iOS5之后才出现的一个框架,它提供了对象-关系映射(ORM)的功能,即能够将OC对象转化成数据,保存在SQLite数据库文件中,也能够将保存在数据库中的数据还原成OC对 ...
- Core Data的一些常见用法
一.简介 Core Data是一个纯粹的面向对象框架,其本质就是一个ORM(对象关系映射:Object Relational Mapping),能以面向对象的方式操作SQLite数据库.在实际开发中绝 ...
- Core Data 使用映射模型
Core Data 使用映射模型 如果新版本的模型存在较复杂的更改,可以创建一个映射模型,通过该模型指定源模型如何映射到目标模型. 创建映射模型,新建File, Core Data 选择Mappin ...
- SELF, self in CORE DATA
Predicate SELF Represents the object being evaluated. CORE DATA Retrieving Specific Objects If your ...
- Core Data浅谈初级入门
Core Data是iOS5之后才出现的一个框架,它提供了对象-关系映射(ORM)的功能,即能够将OC对象转化成数据,保存在SQLite数据库文件中,也能够将保存在数据库中的数据还原成OC对象.在此数 ...
- Core Data
• Core Data 是 iOS SDK 里的一个很强大的框架,允许程序员 以面向对象 的方式储存和管理数据 .使用 Core Data 框架,程序员可以很轻松有效 地通过面向对象的接口 ...
- iOS开发中的4种数据持久化方式【二、数据库 SQLite3、Core Data 的运用】
在上文,我们介绍了ios开发中的其中2种数据持久化方式:属性列表.归档解档.本节将继续介绍另外2种iOS持久化数据的方法:数据库 SQLite3.Core Data 的运 ...
- 我为什么用 SQLite 和 FMDB 而不用 Core Data
凭良心讲,我不能告诉你不去使用Core Data.它不错,而且也在变好,并且它被很多其他Cocoa开发者所理解,当有新人加入你的组或者需要别人接手你的项目的时候,这点很重要.更重要的是,不值得花时间和 ...
- Core Data 概述
Core Data是一个模型层的技术.Core Data帮助你建立代表程序状态的模型层.Core Data也是一种持久化技术,它能将模型对象的状态持久化到磁盘,但它最重要的特点是:Core Data不 ...
随机推荐
- 读书笔记-----Java并发编程实战(一)线程安全性
线程安全类:在线程安全类中封装了必要的同步机制,客户端无须进一步采取同步措施 示例:一个无状态的Servlet @ThreadSafe public class StatelessFactorizer ...
- SQL in查询报告类型转换失败的3种解决办法
-- in查询 nvarchar转int 错误 (NodeId 为 int 类型) ) = '3,5,6,' )' SELECT ID , NodeName FROM WF_WorkFlowNode ...
- [BZOJ2173]整数的lqp拆分
[题目描述] lqp在为出题而烦恼,他完全没有头绪,好烦啊… 他首先想到了整数拆分.整数拆分是个很有趣的问题.给你一个正整数N,对于N的一个整数拆分就是满足任意m>0,a1 ,a2 ,a3…am ...
- 利用腾讯企业邮箱开放API获取账户未读邮件数初探
公司一直使用腾讯提供的免费企业邮箱服务,今天用管理员帐户登录后发现,原来现在腾讯的企业邮箱也开放了部分API 你可以通过开放接口实现以下功能: 数据同步 数据同步可以帮助你同步部门成员信息,你还可以创 ...
- unity中的mesh合并
在分析shadowgun时,无意中发现所有的环境建筑运行后,都被合并成一个叫做 "Combined Mesha (root: scene)" 的mesh了,但是没有发现任何合并的脚 ...
- Java中的包
包:定义包用package关键字. 1:对类文件进行分类管理. 2:给类文件提供多层名称空间. 如果生成的包不在当前目录下,需要最好执行classpath,将包所在父目录定义到classpath变量中 ...
- MacOS下的生活——RescueTime,时间规划利器
前段时间Yxj同学给我推荐了一款可以记录电脑及手机使用时间分类的软件,据说Mac平台下也支持,当时就有了兴趣,但是好像因为什么事给耽搁了,知道今天下午看到Yxj在看这个软件记录的自己的时间表,才觉得这 ...
- Bzoj 1612: [Usaco2008 Jan]Cow Contest奶牛的比赛 传递闭包,bitset
1612: [Usaco2008 Jan]Cow Contest奶牛的比赛 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 891 Solved: 590 ...
- ACM2096
#include<iostream> int main() { using namespace std; int a,b,count; cin>>count; while(co ...
- 天津Uber优步司机奖励政策(1月18日~1月24日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...