Swift — 4 —核心数据—第3部分创建Singleton Core Data和重构插入,更新,删除操作
如果您想进行完整的iOS培训,可以通过以下详细信息与我联系,我会使用目标C或Swift提供实时iOS应用培训
skype:alok.upadhyay32
邮件:meiosdose@gmail.com
应用程式:+ 91–7838552946
大家好😀。 在第2部分中,我们了解了基本的核心数据概念以及插入,更新和删除操作。 在开始对核心数据进行单元测试之前,我们必须松耦合代码。 最终将使我们的视图控制器类也变轻。 下载适用于Starter的第2部分代码。
在这一部分中,我们将在单独的类中分离与核心数据相关的业务逻辑。 最终源代码在本教程的结尾。
请输入☕和开始代码–
在您的项目中添加一个文件,并将其命名为“ CoreDataManager”。
复制以下代码并将其粘贴到“ CoreDataManager”。
进口基金会
导入CoreData
导入UIKit
类CoreDataManager {
// 1
静态让sharedManager = CoreDataManager()
// 2。
private init(){} //阻止客户端创建另一个实例。
// 3
懒惰的varpersistentContainer:NSPersistentContainer = {
让容器= NSPersistentContainer(名称:“ PersonData”)
container.loadPersistentStores(completionHandler:{(storeDescription,error)在
如果让error = error as NSError? {
fatalError(“未解决的错误\(错误),\(error.userInfo)”)
}
})
返回容器
}()
// 4
func saveContext(){
让上下文= CoreDataManager.sharedManager.persistentContainer.viewContext
如果context.hasChanges {
做{
尝试context.save()
} {
//用代码替换此实现,以正确处理错误。
// fatalError()使应用程序生成崩溃日志并终止。 尽管此功能在开发过程中可能很有用,但您不应在运输应用程序中使用此功能。
让nserror =错误为NSError
fatalError(“未解决的错误\(nserror),\(nserror.userInfo)”)
}
}
}
}
让我们了解发生了什么事:
- 我们正在创建一个静态let ,以便sharedManager具有相同的实例 , 并且不能更改 。
- 使用private关键字,这样就不会错误地初始化此类。 如果在某个地方您将尝试再次对其进行初始化,则会出现编译时错误。
- 初始化NSPersistentContainer ,从而延迟初始化完整的核心数据堆栈。 persistentContainer对象仅在需要时才被初始化。 我已经在第1部分中进行了详细介绍。
- 保存上下文方法会将我们未提交的更改保存在核心数据存储中。 我已经在第1部分中进行了详细介绍。
由于我们已将与核心数据相关的代码放在单独的文件CoreDataManager中,因此我们将从AppDelegate文件中删除所有与核心数据相关的代码。
- 删除导入的CoreData
- 删除懒惰的varpersistentContainer:NSPersistentContainer = {……………………}()
- 更改applicationWillTerminate如下:
func applicationWillTerminate(_ application:UIApplication){
//在应用程序即将终止时调用。 如果合适,保存数据。 另请参阅applicationDidEnterBackground:。
//在应用程序终止之前将更改保存在应用程序的托管对象上下文中。
CoreDataManager.sharedManager.saveContext()
}
您的AppDelegate文件应如下所示:
导入UIKit
@UIApplicationMain
类AppDelegate:UIResponder,UIApplicationDelegate {
var window:UIWindow?
func application(_ application:UIApplication,didFinishLaunchingWithOptions launchOptions:[UIApplicationLaunchOptionsKey:Any]?)->布尔{
//应用程序启动后进行自定义的替代点。
返回真
}
func applicationWillResignActive(_ application:UIApplication){
//当应用程序即将从活动状态变为非活动状态时发送。 对于某些类型的临时中断(例如打来的电话或SMS消息),或者当用户退出应用程序并开始过渡到后台状态时,可能会发生这种情况。
//使用此方法可以暂停正在进行的任务,禁用计时器并使图形渲染回调无效。 游戏应使用此方法暂停游戏。
}
func applicationDidEnterBackground(_ application:UIApplication){
//使用此方法释放共享资源,保存用户数据,使计时器无效以及存储足够的应用程序状态信息,以防您的应用程序在以后终止时恢复到当前状态。
//如果您的应用程序支持后台执行,则在用户退出时将调用此方法,而不是applicationWillTerminate:。
}
func applicationWillEnterForeground(_ application:UIApplication){
//作为从后台到活动状态的过渡的一部分调用; 在这里,您可以撤消输入背景时所做的许多更改。
}
func applicationDidBecomeActive(_应用程序:UIApplication){
//重新启动应用程序处于非活动状态时已暂停(或尚未启动)的所有任务。 如果该应用程序以前在后台运行,则可以选择刷新用户界面。
}
func applicationWillTerminate(_ application:UIApplication){
//在应用程序即将终止时调用。 如果合适,保存数据。 另请参阅applicationDidEnterBackground:。
//在应用程序终止之前将更改保存在应用程序的托管对象上下文中。
CoreDataManager.sharedManager.saveContext()
}
}
看看现在有多少细长的AppDelegate文件looking
运行您的项目并查看错误😡
我们收到这些错误消息是因为我们更改了AppDelegate文件,而我们仍未在ViewController类中进行更改。
打开ViewController类并搜索
appDelegate.persistentContainer.viewContext
将appDelegate.persistentContainer.viewContext替换为
CoreDataManager.sharedManager.persistentContainer.viewContext
构建并运行,它现在应该可以工作。 😀
我们仍然在ViewController中收到一些警告,因此我们需要删除与appDelegate相关的代码。
搜索并删除任何您发现以下代码的地方
卫队让appDelegate = UIApplication.shared.delegate为? AppDelegate else {
返回
}
构建并运行您的代码,它现在应该可以正常工作。
现在,我们需要在CoreDataManager类中编写insert,update,delete和fetch方法 。 那就是我们将重构ViewController类。
插入
从ViewController复制代码并将其粘贴到CoreDataManagerClass中。
func save(name:String,ssn:Int16){
/ * 1。
在可以从核心数据存储中保存或检索任何内容之前,首先需要动手使用NSManagedObjectContext。 您可以将托管对象上下文视为用于处理托管对象的内存“便签本”。
可以考虑将新的托管对象保存到Core Data中的过程分为两个步骤:首先,将新的托管对象插入托管对象上下文中; 然后,对闪亮的新托管对象感到满意之后,您可以“提交”托管对象上下文中的更改,以将其保存到磁盘。
Xcode已经生成了一个托管对象上下文,作为新项目模板的一部分。 请记住,只有在开始时选中“使用核心数据”复选框,才会发生这种情况。 此默认托管对象上下文作为应用程序委托中NSPersistentContainer的属性存在。 要访问它,您首先需要获得对应用程序委托的引用。
* /
让managedContext = CoreDataManager.sharedManager.persistentContainer.viewContext
/ *
NSEntityDescription对象与特定的类实例相关联
类
NSEntityDescription
核心数据中实体的描述。
在此处检索具有给定名称的实体的人
* /
让实体= NSEntityDescription.entity(forEntityName:“人”,
在:managedContext)!
/ *
初始化托管对象并将其插入指定的托管对象上下文中。
初始化(实体:NSEntityDescription,
insertInto上下文:NSManagedObjectContext?)
* /
让person = NSManagedObject(entity:实体,
insertInto:managedContext)
/ *
手持NSManagedObject之后,您可以使用键值编码来设置name属性。 您必须完全按照数据模型中显示的方式拼写KVC密钥(在这种情况下为名称)
* /
person.setValue(名称,forKeyPath:“名称”)
person.setValue(ssn,forKeyPath:“ ssn”)
/ *
您可以将更改提交给person并通过在托管对象上下文上调用save来保存到磁盘。 注意save会引发错误,这就是为什么您在do-catch块中使用try关键字调用它的原因。 最后,将新的托管对象插入people数组,以便在重新加载表视图时显示该对象。
* /
做{
尝试managedContext.save()
people.append(人)
tableView.reloadData()
}将let错误捕获为NSError {
print(“无法保存。\(错误),\(error.userInfo)”)
}
}
我们不需要tableView,people.append..blah之类的代码。
我们将对上面的代码进行细微的更改,下面是固定版本。
func insertPerson(name:String,ssn:Int16)->人员? {
/ * 1。
在可以从核心数据存储中保存或检索任何内容之前,首先需要动手使用NSManagedObjectContext。 您可以将托管对象上下文视为用于处理托管对象的内存“便签本”。
可以考虑将新的托管对象保存到Core Data中的过程分为两个步骤:首先,将新的托管对象插入托管对象上下文中; 然后,对闪亮的新托管对象感到满意之后,您可以“提交”托管对象上下文中的更改,以将其保存到磁盘。
Xcode已经生成了一个托管对象上下文,作为新项目模板的一部分。 请记住,只有在开始时选中“使用核心数据”复选框,才会发生这种情况。 此默认托管对象上下文作为应用程序委托中NSPersistentContainer的属性存在。 要访问它,您首先需要获得对应用程序委托的引用。
* /
让managedContext = CoreDataManager.sharedManager.persistentContainer.viewContext
/ *
NSEntityDescription对象与特定的类实例相关联
类
NSEntityDescription
核心数据中实体的描述。
在此处检索具有给定名称的实体的人
* /
让实体= NSEntityDescription.entity(forEntityName:“人”,
在:managedContext)!
/ *
初始化托管对象并将其插入指定的托管对象上下文中。
初始化(实体:NSEntityDescription,
insertInto上下文:NSManagedObjectContext?)
* /
让person = NSManagedObject(entity:实体,
insertInto:managedContext)
/ *
手持NSManagedObject之后,您可以使用键值编码来设置name属性。 您必须完全按照数据模型中显示的方式拼写KVC密钥(在这种情况下为名称)
* /
person.setValue(名称,forKeyPath:“名称”)
person.setValue(ssn,forKeyPath:“ ssn”)
/ *
您可以将更改提交给person并通过在托管对象上下文上调用save来保存到磁盘。 注意save会引发错误,这就是为什么您在do-catch块中使用try关键字调用它的原因。 最后,将新的托管对象插入people数组,以便在重新加载表视图时显示该对象。
* /
做{
尝试managedContext.save()
返回人为? 人
}将let错误捕获为NSError {
print(“无法保存。\(错误),\(error.userInfo)”)
返回零
}
}
现在打开ViewController类并进行更改
func save(名称:字符串,ssn:Int16)
按照下面的代码:
func save(name:String,ssn:Int16){
// 1
let person = CoreDataManager.sharedManager.insertPerson(name:name,ssn:ssn)
// 2
如果人!=无{
people.append(人!)// 3
tableView.reloadData()// 4
}
}
立即查看代码之美。 重量很轻。 是不是
- 我们正在调用CoreDataManager类的insertPerson方法,它将返回一个可选的person对象。
- 在解包之前,我们必须确保从运行时崩溃中将其保存为nil。 如果不是零,则仅强行解开包装。 您还可以使用可选绑定来获取未包装的值。
- 在表视图数据源数组中添加此对象
- 最后重新加载表。
让我们运行它,看看一切正常。 是的,到目前为止一切都很好。
让我们重构更新代码。
更新资料
在ViewController中搜索
func update(name:String,ssn:Int16,person:Person)
方法。 我们将按原样复制此方法并将其粘贴到CoreDataManager类中。
func update(name:String,ssn:Int16,person:Person){
/ * 1。
在可以从核心数据存储中保存或检索任何内容之前,首先需要动手使用NSManagedObjectContext。 您可以将托管对象上下文视为用于处理托管对象的内存“便签本”。
可以考虑将新的托管对象保存到Core Data中的过程分为两个步骤:首先,将新的托管对象插入托管对象上下文中; 然后,对闪亮的新托管对象感到满意之后,您可以“提交”托管对象上下文中的更改,以将其保存到磁盘。
Xcode已经生成了一个托管对象上下文,作为新项目模板的一部分。 请记住,只有在开始时选中“使用核心数据”复选框,才会发生这种情况。 此默认托管对象上下文作为应用程序委托中NSPersistentContainer的属性存在。 要访问它,您首先需要获得对应用程序委托的引用。
* /
让上下文= CoreDataManager.sharedManager.persistentContainer.viewContext
做{
/ *
手持NSManagedObject之后,您可以使用键值编码来设置name属性。 您必须完全按照数据模型中显示的方式拼写KVC密钥(在这种情况下为名称)
* /
person.setValue(名称,forKey:“名称”)
person.setValue(ssn,forKey:“ ssn”)
print(“ \(person.value(forKey:” name“))”)
print(“ \(person.value(forKey:” ssn“))”)
/ *
您可以将更改提交给person并通过在托管对象上下文上调用save来保存到磁盘。 注意save会引发错误,这就是为什么您在do-catch块中使用try关键字调用它的原因。 最后,将新的托管对象插入people数组,以便在重新加载表视图时显示该对象。
* /
做{
尝试context.save()
打印(“保存!”)
}将let错误捕获为NSError {
print(“无法保存\(错误),\(error.userInfo)”)
} {
}
} {
打印(“请求错误:\(错误)”)
}
}
现在打开ViewController文件并更改
func update(name:String,ssn:Int16,person:Person)
方法按以下实现:
func update(name:String,ssn:Int16,person:Person){
CoreDataManager.sharedManager.update(名称:名称,ssn:ssn,人:人)
}
看看代码人! 通过这种方法,我们减少了很多负担。 干杯🙂
构建它,插入一些数据并更新它,它应该可以工作。
现在,让更改删除实现并使CoreDataManager类中的删除可用。 从ViewController复制完整的delete(person 🙂函数及其实现,并将其粘贴到CoreDataManager类中。
func delete(person:Person){
让managedContext = CoreDataManager.sharedManager.persistentContainer.viewContext
做{
managedContext.delete(人)
} {
//对错误情况做出响应
打印(错误)
}
做{
尝试managedContext.save()
} {
//对错误情况做出响应
}
}
解释很简单。 获取托管对象上下文。 调用delete方法并将person对象作为参数传递。 最后,调用do-try-catch来保存ManagedContext的未提交更改。
现在改变
func delete(person:Person)
实现如下:
func delete(person:Person){
CoreDataManager.sharedManager.delete(person:person)
}
您在看这段代码😎。 重量轻。 让我们再次构建,运行和测试插入,更新和删除代码,一切正常。
最后,让我们快速重构fetchAllPersons()的代码,然后进行func delete(ssn:String)。
打开CoreDataManager类,然后粘贴以下代码:
func fetchAllPersons(){
/ *在使用Core Data进行任何操作之前,需要一个托管对象上下文。 * /
让managedContext = CoreDataManager.sharedManager.persistentContainer.viewContext
/ *顾名思义,NSFetchRequest是负责从Core Data进行提取的类。
使用init(entityName :)初始化获取请求,将获取特定实体的所有对象。 这是您在此处获取所有Person实体的操作。
* /
让fetchRequest = NSFetchRequest (entityName:“ Person”)
/ *您将获取请求移交给托管对象上下文以进行繁重的工作。 fetch(_ :)返回满足fetch请求指定条件的托管对象数组。* /
做{
人员=尝试managedContext.fetch(fetchRequest)
}将let错误捕获为NSError {
print(“无法获取。\(错误),\(error.userInfo)”)
}
}
在上面的代码中进行小的更改:
func fetchAllPersons()-> [Person]?{
/ *在使用Core Data进行任何操作之前,需要一个托管对象上下文。 * /
让managedContext = CoreDataManager.sharedManager.persistentContainer.viewContext
/ *顾名思义,NSFetchRequest是负责从Core Data进行提取的类。
使用init(entityName :)初始化获取请求,将获取特定实体的所有对象。 这是您在此处获取所有Person实体的操作。
* /
让fetchRequest = NSFetchRequest (entityName:“ Person”)
/ *您将获取请求移交给托管对象上下文以进行繁重的工作。 fetch(_ :)返回满足fetch请求指定条件的托管对象数组。* /
做{
让人们=尝试managedContext.fetch(fetchRequest)
还给人吗? [人]
}将let错误捕获为NSError {
print(“无法获取。\(错误),\(error.userInfo)”)
返回零
}
}
现在我们将重构使用谓词的delete函数的代码。
将以下方法粘贴到CoreDataManager类中。
func delete(ssn:String)-> [人员]? {
/ *获取对appdelegate文件的引用* /
/ *获取管理对象上下文的引用* /
让managedContext = CoreDataManager.sharedManager.persistentContainer.viewContext
/ *初始化获取请求* /
让fetchRequest = NSFetchRequest (entityName:“ Person”)
/ *使用NSPredicate传递您的条件。 我们只想删除符合我们条件的记录* /
fetchRequest.predicate = NSPredicate(格式:“ ssn ==%@”,ssn)
做{
/*managedContext.fetch(fetchRequest)将返回人员对象数组[personObjects] * /
让item =试试ManagedContext.fetch(fetchRequest)
var arrRemovedPeople = [Person]()
为我在{
/ *调用删除方法(aManagedObjectInstance)* /
/ *这里我是托管对象实例* /
managedContext.delete(i)
/ *最后保存上下文* /
尝试managedContext.save()
/ *还更新您的数组* /
arrRemovedPeople.append(i as!Person)
}
返回arrRemovedPeople
}将let错误捕获为NSError {
print(“无法获取。\(错误),\(error.userInfo)”)
返回零
}
}
改变实施
删除(ssn:字符串)
在ViewController类中,如下所示:
func delete(ssn:String){
让arrRemovedObjects = CoreDataManager.sharedManager.delete(ssn:ssn)
people = people.filter({(param)-> Bool in
if(arrRemovedObjects?.contains(param as!Person))!{
返回假
}其他{
返回真
}
})
}
说明—我们正在使用快速的高阶函数过滤器,从人员数组中删除arrRemovedObjects的对象。
var array1 = [“ a”,“ b”,“ c”,“ d”,“ e”]
让array2 = [“ a”,“ c”,“ d”]
array1 = array1.filter {!array2.contains($ 0)} //输出[b,e]
您也可以使用for循环create创建自己的逻辑。
让我们运行我们的代码并测试所有操作。 每件事都是完美的。
😉。
我也在这里写http://iosdose.com/wp/2018/03/29/swift-4-core-data-part-3-creating-a-singleton-coredatamanager-class-refactoring-insert-update-delete-操作/
如承诺的源代码在这里。
请通过评论支持我们,喜欢并分享我们的Facebook页面。
如果您想进行完整的iOS培训,可以通过以下详细信息与我联系,我会使用目标C或Swift提供实时iOS应用培训
skype:alok.upadhyay32
邮件:meiosdose@gmail.com
应用程式:+ 91–7838552946