建立一个iOS工程,勾选Use Core Data。正则表达式
工程建立完后,XCode将为咱们生成一个xcdatamodeld文件用于建立实体。咱们能够在这里编辑实体,并产生托管对象类。同时,XCode也在AppDelegate.Swift中添加了一些用于支持CoreData的代码。sql
我在这里所用的办法是经过辅助类来设置Core Data,这样的话,你就能够将这种办法运用到本身的项目中了。这也使得Core Data组件变的模块化,并且易于移植。咱们将经过应用程序委托来惰性地(lazily)建立CoreDataHelper类的实例。下面就来看咱们的方法二数据库
这种实例可用来完成下列事项:
一、初始化托管对象模型
二、根据托管对象模型来建立持久化存储区,并据此初始化持久化存储协调器
三、根据化持久化存储协调器来初始化托管对象上下文swift
咱们先建立CoreDataHelper.Swift文件,而且将Subclass类名为CoreDataHelper。后端
import CoreData class CoreDataHelper:NSObject { // MARK: - Core Data stack // 这个目录用来存放应用程序Core Data存储文件,在当前事例中,会在应用程序的Document目录下生成名为“FoodPin.Coredata”文件。 lazy var applicationDocumentsDirectory: NSURL = { let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) return urls[urls.count-1] as! NSURL }() // 应用程序的托管对象模型。 lazy var managedObjectModel: NSManagedObjectModel = { let modelURL = NSBundle.mainBundle().URLForResource("FoodPin", withExtension: "momd")! return NSManagedObjectModel(contentsOfURL: modelURL)! }() //持久化协调器 lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = { var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel) let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("FoodPin.sqlite") var error: NSError? = nil var failureReason = "There was an error creating or loading the application's saved data." if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error: &error) == nil { coordinator = nil // Report any error we got. let dict = NSMutableDictionary() dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" dict[NSLocalizedFailureReasonErrorKey] = failureReason dict[NSUnderlyingErrorKey] = error error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict as [NSObject : AnyObject]) NSLog("Unresolved error \(error), \(error!.userInfo)") abort() } return coordinator }() //托管对象上下文 lazy var managedObjectContext: NSManagedObjectContext? = { let coordinator = self.persistentStoreCoordinator if coordinator == nil { return nil } var managedObjectContext = NSManagedObjectContext() managedObjectContext.persistentStoreCoordinator = coordinator return managedObjectContext }() // MARK: - Core Data Saving support func saveContext () { if let moc = self.managedObjectContext { var error: NSError? = nil if moc.hasChanges && !moc.save(&error) { NSLog("Unresolved error \(error), \(error!.userInfo)") abort() } } } }
我是绝对绝对不会告诉你上边的这段代码是我从AppDelegate.Swift中将有关CoreData的部分剪贴出来生成新的CoreDataHelper类的。数组
command + n
以后选择iOS中的Core Data里的Data Model文件,点击Next。
填写文件名称,默认名称是Model。点击Create以后在工程中就能够看到一个.xcdatamodeld
为后缀的文件了。安全
托管对象模型由一系列实体描述对象构成,这种对象就叫作实体。实体用来建立托管对象,有了托管对象以后咱们能够用Swift代码来操做其中的数据了。app
托管对象模型能够拥有一个或者多个实体,每一个应用程序的实体数量会有所差异。在制做托管对象以前,首先要把每个实体设计好。实体的设计与传统的数据库中数据表的设计是类似的。dom
实体的属性必须有特定的数据类型,若是想从实体中建立托管对象,那么咱们一般会根据实体来建立NSManagedObject的子类,但这并非强制性的。采用NSManagedObject的子类确实有好处,好比说能够在托管对象后面使用“点符号”来访问相关属性,这样可让代码便于阅读。编辑器
按照下面的步骤来添加一个实体:
一、选定Model.xcdatamodeld
二、点击Add Entity
三、把实体的名称改成Entity
选择适合的属性值在你的属性名称后边。
若是在Properties中勾选了这一项,那么该属性就不会写入持久化存储区了。“不写入持久化存储区”听上去有些奇怪,可是有时,只须要吧特性留在托管对象上下文里面就好了。比方说,你须要计算某个临时的值,而这种值就能够放在transient特性中。
Optional特性并不必定要有值。全部的特性在刚建出来的时候都是Optional特性。若是某一个不是Optiona特性,那么在把这非Optional特性放回存储区的时候,它必须具有有效的值才行。
系统会优化Indexed特性以提高搜索效率,但代价是要在底层的持久化存储区占用额外的空间。这些额外的空间的大小要根据待索引的数据量来定。若是不打算搜索某个属性,那么就不要勾选Indexed,这样能够节省一些空间。
你可使用Validation中的各个选项来阻止不合理的数据进入持久化存储区。每一种数值型的属性都支持相同的Validation选项,也就是能够规定其最小值和最大值。同理,对于字符串类型或者日期类型的属性来讲,能够限定其字符串长度和日期范围。
Reg. Ex.是Regular Expression(正则表达式)的缩写,他不只可以限定字符串的最小长度以及最大长度,并且还能实现不少验证功能。通常来讲,咱们会用正则表达式来判断属性中的字符串值是否是能与某个特定的模式相匹配。匹配成功了才能将其写入持久化存储区。
除了可变数据类型与二进制数据以外,其他类型的属性均可以具有默认值。
开启了这个选项以后,类型为二进制数据的属性就能够把大量数据保存在持久化存储区以外了。但若是底层的持久化存储区是XML格式(iOS不支持这种格式的存储区),那么该选项就不起做用了。
托管对象模型就位以后,咱们就该根据Entity实体来建立NSManagedObject的子类了。
一、选中Entity实体。
二、点击Editor>Create NSManagedObject Subclass菜单项。
三、确保Model被选中,而后点击Next。
四、屡次点击下一步以后,会在项目中生成Entity.swift文件。
在这中间要强调的一点是,要不要勾选 Use scalar properties for primitive data types。
勾选上这个选项以后就是使用的是你在定义的时候使用的原始数据类型。
若是没有勾选的话,就会存在类型的转化,转换状况以下
• String maps to String • Integer 16/32/64, Float, Double and Boolean map to NSNumber • Decimal maps to NSDecimalNumber • Date maps to NSDate • Binary data maps to NSData • Transformable maps to AnyObject
本身试一下,看看勾选以后和没有勾选生成的Entity.swift文件有什么区别。
全部的事情都准备好了以后,如今能够新建一些托管对象了。
新对象是由NSEntityDescription按照指定的名称并根据某个特定的实体而建立出来的。除了要指定对象所依据的实体以外,还须要提供托管对象上下文,建立好的托管对象将会放在那个上下文里面。
let coredataHelper = CoreDataHelper() if let managedobjectcontext = coredataHelper.managedObjectContext{ var object = NSEntityDescription.insertNewObjectForEntityForName("Entity", inManagedObjectContext: managedobjectcontext) as! Entity object.name = "Hello World Core Data" var e:NSError? if !managedobjectcontext.save(&e) { println("okCould not save \(e), \(e!.userInfo)") }else{ println("数据存储成功,哦也") } }
按照下列步骤开启SQL Debug模式
一、点击Product>Scheme>Edit Scheme ...
二、点击Run Grocery Dude,并切换到Arguments分页。
三、点击Arguments Passed On Launch区域中的“+”按钮,以新增参数。
四、输入新参数 -com.apple.CoreData.SQLDebug 3
,而后点击OK。
如今咱们已经开启了第三级的SQL Debug模式,而后从新运行程序,查看控制台输出了什么。
想操做托管对象上下文中的现有数据,就必须先把它获取(fetch)出来。加入待获取的数据没有放在上下文中,那么Core Data会从底层的持久化存储区里面把它拿过来,这个过程对开发者来讲是透明的。
要执行获取操做,就要有NSFetchRequest实例,改实例会返回[AnyObject]
,这个数组里面的元素都是托管对象。在执行获取操做的时候NSFetchRequest会根据特定的实体,把每一个托管对象都放在[AnyObject]
这个数组里面,而且返回给调用者。
var fetchRequest = NSFetchRequest(entityName: "Entity") var fetchObjects = managedobjectcontext.executeFetchRequest(fetchRequest, error: &e) as! [Entity] for info in fetchObjects{ println("name: \(info.name)") println("+++++++++++++++++++++++") //修改 info.name = "这块显卡有点冷" if !managedobjectcontext.save(&e){ println("不能保存\(e!.localizedDescriptoin)") } }
NSFetchRequest执行完毕以后会返回一个NSArray
,而NSArray
自己就支持其中的元素进行排序。咱们能够给NSFetchRequest
配置排序描述符,这样的话。NSFetchRequest
就能够直接按特定方式获取到托管对象进行排序了。这个描述符是做为NSSortDescriptor
的实例传给NSFetchRequest
的。
有时咱们并不想把与某个实体有关的所有对象都获取过来,这时能够经过谓词来筛选。咱们采用NSPredicate
实例来定义谓词,并将其传给NSFetchRequest
实例。有了谓词以后,获取请求就会根据谓词中的标准限定获取到的托管对象的数量。
若是咱们每一次获取托管对象时都要使用手工编写谓词格式确实很累人哇。幸亏的是,Xcode的Data Model Designer有预约义获取请求的功能。这些可复用的模版比谓词更容易配置,并且还能减小重复代码。
建立获取请求模版:
选中.xcdatamodeld。
点击Editot > Add Fetch Rquest。
而后设置请求模版的名称。
点击+按钮来配置获取请求模版。
要想使用获取请求模版,须要先给托管对象模型发送消息,告诉他将要使用的模版叫作什么名字。发送完消息以后,就能够在返回的NSFetchRequest上面操做了。因为这种获取请求是根据模版建立出来的,因此咱们无需经过向其发送谓词来执行筛选操做。
let fetchRequest3 = managedObjectModel.fetchRequestTemplateForName("Name")
struct NSFetchRequestResultType : OptionSetType { init(rawValue rawValue: UInt) static var ManagedObjectResultType: NSFetchRequestResultType { get } //返回 ManagedObject 这个是默认的 static var ManagedObjectIDResultType: NSFetchRequestResultType { get} //返回 unique identifiers instead of full- fledged managed objects. static var DictionaryResultType: NSFetchRequestResultType { get } //返回 字典类型 static var CountResultType: NSFetchRequestResultType { get } // 返回 Returns the count of the objects that match the fetch request. }
若想删除托管对象,只须要在包含对象的上下文中调用deleteObject
或者deleteObjects
。而后用上下文的save方法保存更新数据库。
关系是用来连接实体的。在托管对象模型中使用关系。
咱们把界面的Editor Style 改成 Graph,按下control键,用鼠标从一个 实体托向另外一个实体。
当编辑器界面处于Graph风格时,在两实体之间建立的关系是双向关系。若是在Table风格的编辑器界面中建立关系,那么建立出来的可能就是单向关系,此时若是须要创建双向关系,那么还必须手动添加反向的那一条关系。
把两个实体关联起来以后,咱们就能够经过关系来访问相关实体的属性了。
接下来的问题就是,要想清楚每一个方向上的关系是一对多,仍是一对一。想清楚这个问题以后,你应该就能给关系起一个更为合适的名字。一对多的关系,不限制目标对象的数量,而一对一的关系则会把目标对象的数量限定为一个。
在配置的时候必定要注意Delete Rule。当咱们删除某个对象时,该规则决定了与之相关的那些对象因该如何处理。可供选择的Delete规则有下面几种:
大多数时候均可以采用这种默认的删除规则。若是删除了某一个对象,而该对象与其它对象的关系有受制于Nullify规则,那么这些对象就会把指向该对象的关系清空。
这种删除规则会沿着关系来传播删除操做
若是尚有其它对象与某个对象关联,那么这种删除规则会阻止开发者删除该对象。
这是一种奇怪的删除规则,它会致使对象图处于不一致状态。假如运用了这条删除规则,那么在删除某个对象以后,开发者必须手动设置反向的关系,以确保它们都指向有效的对象。
只有在尝试保存上下文的时候,系统才会去检查删除规则是否生效,假若发生违规,则会产生 NSCocoaErrorDomain
错误,他的错误代码是1600,若是想解决这个错误,就要在删除以前确保该对象能够安全的移除。
在对象保存到持久化存储区以前,它们必须经过验证。假如某个对象未能经过验证,那么系统就会抛出domain为NSCocoaErrorDomain
的错误。
与类同样,实体也能够继承自父实体。这个功能有助于简化数据模型。子实体会自动继承父实体的各类属性。在底层的SQLite存储区里,父-子体系中的实体都会存储到同一张数据表里。
若是不想令父实体实例化,那么能够将其标注为抽象的。只有可以肯定父实体在代码中毫无心义时,才应该启用这个选项。