iOS CoreData 增删改查详解

最近在学习CoreData, 因为项目开发中需要,特意学习和整理了一下,整理出来方便以后使用和同行借鉴。目前开发使用的Swift语言开发的项目。所以整理出来的是Swift版本,OC我就放弃了。 虽然Swift3 已经有了,目前整理的这个版本是Swift2 的。Swift 3 的话有些新特性。 需要另外调整,后续有时间再整理。

继承CoreData有两种方式: 

创建项目时集成

这种方式是自动继承在AppDelegate里面,调用的使用需要通过UIApplication的方式来获取AppDelegate得到Conext。本人不喜欢这种方式,不喜欢AppDelegate太多代码堆在一起,整理了一下这种方式

将CoreData继承的代码单独解耦出来做一个单例类

项目结构图

项目文件说明 
CoreData核心的文件就是 
1.XPStoreManager(管理CoreData的单例类) 
2.CoredataDemo.xcdatamodeld (CoreData数据模型文件)
 3.Student+CoreDataProperites.swift和Student.swift (学生对象) 
4.ViewController.swift 和Main.storyboard是示例代码

细节代码 

1. XPStoreManager.swift
CoreData数据管理单例类

//

// XPStoreManager.swift

// CoreDataDemo

//

// Created by xiaopin on 16/9/16.

// Copyright © 2016年 xiaopin.cnblogs.com. All rights reserved.

//

import CoreData

/// 本地数据库管理类:默认是写在AppDelegate的,可以这样分离出来

class XPStoreManager {

 //单例写法

 static let shareInstance = XPStoreManager()

 private init() {

 }

 // MARK: - Core Data stack

 lazy var applicationDocumentsDirectory: NSURL = {

  // The directory the application uses to store the Core Data store file. This code uses a directory named "com.pinguo.CoreDataDemo" in the application's documents Application Support directory.

  let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)

  print("\(urls[urls.count-1])")

  return urls[urls.count-1]

 }()

 lazy var managedObjectModel: NSManagedObjectModel = {

  // The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.

  let modelURL = NSBundle.mainBundle().URLForResource("CoreDataDemo", withExtension: "momd")!

  return NSManagedObjectModel(contentsOfURL: modelURL)!

 }()

 lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {

  // The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.

  // Create the coordinator and store

  let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)

  let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")

  var failureReason = "There was an error creating or loading the application's saved data."

  do {

   try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)

  } catch {

   // Report any error we got.

   var dict = [String: AnyObject]()

   dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"

   dict[NSLocalizedFailureReasonErrorKey] = failureReason

   dict[NSUnderlyingErrorKey] = error as NSError

   let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)

   // Replace this with code to handle the error appropriately.

   // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

   NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")

   abort()

  }

  return coordinator

 }()

 lazy var managedObjectContext: NSManagedObjectContext = {

  // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.

  let coordinator = self.persistentStoreCoordinator

  var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)

  managedObjectContext.persistentStoreCoordinator = coordinator

  return managedObjectContext

 }()

 // MARK: - Core Data Saving support

 func saveContext () {

  if managedObjectContext.hasChanges {

   do {

    try managedObjectContext.save()

   } catch {

    // Replace this implementation with code to handle the error appropriately.

    // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

    let nserror = error as NSError

    NSLog("Unresolved error \(nserror), \(nserror.userInfo)")

    abort()

   }

  }

 }

}

2.AppDelegate.swift

在这个行数中加入一句代码,退出后执行保存一下

func applicationWillTerminate(application: UIApplication) {
  // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
  // Saves changes in the application's managed object context before the application terminates.
  XPStoreManager.shareInstance.saveContext()

 }

3.Student.swift

编写了针对这个学生对象的增删改查

//

// Student.swift

// CoreDataDemo

//

// Created by cdmac on 16/9/12.

// Copyright © 2016年 xiaopin.cnblogs.com. All rights reserved.

//

import Foundation

import CoreData

class Student: NSManagedObject {

 // Insert code here to add functionality to your managed object subclass

 /*

  一般涉及到的情况有:增删改,单对象查询,分页查询(所有,条件查询,排序),对象是否存在,批量增加,批量修改

  */

 /// 判断对象是否存在, obj参数是当前属性的字典

 class func exsitsObject(obj:[String:String]) -> Bool {

  //获取管理数据对象的上下文

  let context = XPStoreManager.shareInstance.managedObjectContext

  //声明一个数据请求

  let fetchRequest = NSFetchRequest(entityName: "Student")

  //组合过滤参数

  let stuId = obj["stuId"]

  let name = obj["name"]

  //方式一

  let predicate1 = NSPredicate(format: "stuId = %@", stuId!)

  let predicate2 = NSPredicate(format: "name = %@", name!)

  //合成过滤条件

  //or ,and, not , 意思是:或与非,懂数据库的同学应该就很容易明白

  let predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [predicate1,predicate2])

  //let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate1,predicate2])

  fetchRequest.predicate = predicate

  //方式二

  //fetchRequest.predicate = NSPredicate(format: "stuId = %@ or name = %@", stuId!, name!)

  //fetchRequest.predicate = NSPredicate(format: "stuId = %@ and name = %@", stuId!, name!)

  do{

   let fetchObjects:[AnyObject]? = try context.executeFetchRequest(fetchRequest)

   return fetchObjects?.count > 0 ? true : false

  }catch {

   fatalError("exsitsObject \(error)")

  }

  return false

 }

 /// 添加对象, obj参数是当前属性的字典

 class func insertObject(obj: [String:String]) -> Bool {

  //如果存在对象了就返回

  if exsitsObject(obj) {

   return false

  }

  //获取管理的数据上下文 对象

  let context = XPStoreManager.shareInstance.managedObjectContext

  //创建学生对象

  let stu = NSEntityDescription.insertNewObjectForEntityForName("Student",

                  inManagedObjectContext: context) as! Student

  //对象赋值

  let sexStr:String

  if obj["sex"] == "男"{

   sexStr = "1"

  }else{

   sexStr = "0"

  }

  let numberFMT = NSNumberFormatter()

  numberFMT.numberStyle = .NoStyle

  stu.stuId = numberFMT.numberFromString(obj["stuId"]!)

  stu.name = obj["name"]

  stu.createtime = NSDate()

  stu.sex = numberFMT.numberFromString(sexStr)

  stu.classId = numberFMT.numberFromString(obj["classId"]!)

  //保存

  do {

   try context.save()

   print("保存成功!")

   return true

  } catch {

   fatalError("不能保存:\(error)")

  }

  return false

 }

 /// 删除对象

 class func deleteObject(obj:Student) -> Bool{

  //获取管理的数据上下文 对象

  let context = XPStoreManager.shareInstance.managedObjectContext

  //方式一: 比如说列表已经是从数据库中获取的对象,直接调用CoreData默认的删除方法

  context.deleteObject(obj)

  XPStoreManager.shareInstance.saveContext()

  //方式二:通过obj参数比如:id,name ,通过这样的条件去查询一个对象一个,把这个对象从数据库中删除

  //代码:略

  return true

 }

 /// 更新对象

 class func updateObject(obj:[String: String]) -> Bool {

  //obj参数说明:当前对象的要更新的字段信息,唯一标志是必须的,其他的是可选属性

  let context = XPStoreManager.shareInstance.managedObjectContext

  let oid = obj["stuId"]

  let student:Student = self.fetchObjectById(Int(oid!)!)! as! Student

  //遍历参数,然后替换相应的参数

  let numberFMT = NSNumberFormatter()

  numberFMT.numberStyle = .NoStyle

  for key in obj.keys {

   switch key {

   case "name":

    student.name = obj["name"]

   case "classId":

    student.classId = numberFMT.numberFromString(obj["classId"]!)

   default:

    print("如果有其他参数需要修改,类似")

   }

  }

  //执行更新操作

  do {

   try context.save()

   print("更新成功!")

   return true

  } catch {

   fatalError("不能保存:\(error)")

  }

  return false

 }

  /// 查询对象

 class func fetchObjects(pageIndex:Int, pageSize:Int) -> [AnyObject]? {

  //获取管理的数据上下文 对象

  let context = XPStoreManager.shareInstance.managedObjectContext

  //声明数据的请求

  let fetchRequest:NSFetchRequest = NSFetchRequest(entityName: "Student")

  fetchRequest.fetchLimit = pageSize //每页大小

  fetchRequest.fetchOffset = pageIndex * pageSize //第几页

  //设置查询条件:参考exsitsObject

  //let predicate = NSPredicate(format: "id= '1' ", "")

  //fetchRequest.predicate = predicate

  //设置排序

  //按学生ID降序

  let stuIdSort = NSSortDescriptor(key: "stuId", ascending: false)

  //按照姓名升序

  let nameSort = NSSortDescriptor(key: "name", ascending: true)

  let sortDescriptors:[NSSortDescriptor] = [stuIdSort,nameSort]

  fetchRequest.sortDescriptors = sortDescriptors

  //查询操作

  do {

   let fetchedObjects:[AnyObject]? = try context.executeFetchRequest(fetchRequest)

   //遍历查询的结果

   /*

   for info:Student in fetchedObjects as! [Student]{

    print("id=\(info.stuId)")

    print("name=\(info.name)")

    print("sex=\(info.sex)")

    print("classId=\(info.classId)")

    print("createTime=\(info.createtime)")

    print("-------------------")

   }

    */

   return fetchedObjects

  }

  catch {

   fatalError("不能保存:\(error)")

  }

  return nil

 }

  /// 根据ID查询当个对象

 class func fetchObjectById(oid:Int) -> AnyObject?{

  //获取上下文对象

  let context = XPStoreManager.shareInstance.managedObjectContext

  //创建查询对象

  let fetchRequest:NSFetchRequest = NSFetchRequest(entityName: "Student")

  //构造参数

  fetchRequest.predicate = NSPredicate(format: "stuId = %@", String(oid))

  //执行代码并返回结果

  do{

   let results:[AnyObject]? = try context.executeFetchRequest(fetchRequest)

   if results?.count > 0 {

    return results![0]

   }

  }catch{

   fatalError("查询当个对象致命错误:\(error)")

  }

  return nil

 }

}

4.ViewController.swift

具体使用:

//

// ViewController.swift

// CoreDataDemo

//

// Created by cdmac on 16/9/11.

// Copyright © 2016年 pinguo. All rights reserved.

//

import UIKit

let cellIdentifiler = "ReuseCell"

class ViewController: UIViewController {

 @IBOutlet weak var txtNo: UITextField!

 @IBOutlet weak var txtName: UITextField!

 @IBOutlet weak var txtSex: UITextField!

 @IBOutlet weak var txtClassId: UITextField!

 @IBOutlet weak var tableView: UITableView!

 var dataArray:[AnyObject]?

 override func viewDidLoad() {

  super.viewDidLoad()

  // Do any additional setup after loading the view, typically from a nib.

  self.dataArray = Student.fetchObjects(0, pageSize: 20)

  self.tableView.reloadData()

 }

 override func didReceiveMemoryWarning() {

  super.didReceiveMemoryWarning()

  // Dispose of any resources that can be recreated.

 }

 @IBAction func addAction(sender: AnyObject) {

  var dic = [String:String]()

  dic["stuId"] = txtNo.text

  dic["name"] = txtName.text

  dic["sex"] = txtSex.text

  dic["classId"] = txtClassId.text

  if Student.insertObject(dic) {

   print("添加成功")

   self.dataArray = Student.fetchObjects(0,pageSize: 20)

   self.tableView.reloadData()

  }else{

   print("添加失败")

  }

 }

 @IBAction func updateAction(sender: AnyObject) {

  var dic = [String:String]()

  dic["stuId"] = txtNo.text

  dic["name"] = txtName.text

  //dic["sex"] = txtSex.text

  dic["classId"] = txtClassId.text

  if Student.updateObject(dic) {

   print("更新成功")

   self.dataArray = Student.fetchObjects(0,pageSize: 20)

   self.tableView.reloadData()

  }else{

   print("更新失败")

  }

 }

}

extension ViewController:UITableViewDelegate,UITableViewDataSource{

 //表格有多少组

 func numberOfSectionsInTableView(tableView: UITableView) -> Int {

  return 1

 }

 //每组多少行

 func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

  if self.dataArray != nil && self.dataArray?.count > 0 {

   return self.dataArray!.count

  }

  return 0

 }

 //高度

 func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {

  return 50

 }

 //单元格加载

 func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

  let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifiler)

  let stu:Student = self.dataArray![indexPath.row] as! Student

  let label1:UILabel = cell?.contentView.viewWithTag(10001) as! UILabel

  let label2:UILabel = cell?.contentView.viewWithTag(10002) as! UILabel

  var sexStr = "男"

  if stu.sex?.intValue != 1 {

   sexStr = "女"

  }

  label1.text = "\(stu.stuId!) \(stu.name!) \(sexStr) \(stu.classId!)"

  label2.text = "http://xiaopin.cnblogs.com"

  return cell!

 }

 //选中

 func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

 }

 func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {

  return true

 }

 func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {

  if editingStyle == .Delete {

   //获取当前对象

   let student:Student = self.dataArray![indexPath.row] as! Student

   //删除本地存储

   Student.deleteObject(student)

   //刷新数据源

   self.dataArray?.removeAtIndex(indexPath.row)

   //self.dataArray = Student.fetchObjects(0, pageSize: 20)

   //删除单元格

   tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)

  }

 }

 func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {

  return .Delete

 }

 func tableView(tableView: UITableView, titleForDeleteConfirmationButtonForRowAtIndexPath indexPath: NSIndexPath) -> String? {

  return "删除"

 }

}

运行效果图

源码下载:CoreDataDemo.zip

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • iOS 雷达效果实例详解

    iOS雷达效果 这段时间新app开始了,有个产品需求是做一个类似如下效果的雷达图: 中间的图片是用户头像,然后需要展示一个雷达扫描的效果. 分析下雷达图的大致构成: 底部一个呈现用户头像的UIImageView 几个颜色渐变的同心圆,这些同心圆. 只需要在雷达视图的drawRect方法里画就可以了 盖在最上层的一个扇形,且扇形的圆心和雷达图视图的圆心是同一个点.扫描效果就是让这个扇形绕圆心转,因此把这个扇形抽成一个单独的类比较好. 同时这个雷达图应该提供两个接口:开始动画,暂停动画.因此雷达图的

  • iOS多级列表实现代码

    在项目开发中,层级列表经常遇到,简单点的二级列表利用UITableView的Header就可以实现,再简单点的三级列表通过对Cell高度进行调整也可以实现三级列表的效果.但遇到多级列表,尤其是层次不明的动态列表就比较麻烦了. 原理 层级列表和树形结构比较类似,不过不是二叉树,而是多叉树.每个节点只需要拥有指向父节点和子节点的两个指针,就能形成一颗树.我们将多级列表中每一级对象看作一个node,node拥有两个属性,分别为父节点和子节点的ID. 每棵树有个一个虚拟的root节点,它的ID为root

  • IOS CocoaPods详解之制作篇

    学会使用别人的Pods依赖库以后,你一定对创建自己的依赖库跃跃欲试,今天就来揭开Pods依赖库创建过程的神秘面纱.整个创建过程都以我实现的一个名称为WZMarqueeView跑马灯效果的view为例,步骤如下: 一.创建自己的github仓库 CocoaPods都托管在github上(官方链接为:https://github.com/CocoaPods),所有的Pods依赖库也都依赖github,因此第一步我们需要创建一个属于自己的github仓库.仓库创建界面如下图: 上图中标了序号的共6处,

  • iOS 开发常用宏总结

    大家都是知道使用宏不仅方便,而且可以提高开发效率.下面总结了iOS开发过程中的一些常用宏,会持续的往里面添加. Objective-C //字符串是否为空 #define kStringIsEmpty(str) ([str isKindOfClass:[NSNull class]] || str == nil || [str length] < 1 ? YES : NO ) //数组是否为空 #define kArrayIsEmpty(array) (array == nil || [array

  • iOS10全新推送功能实现代码

    从iOS8.0开始推送功能的实现在不断改变,功能也在不断增加,iOS10又出来了一个推送插件的开发(见最后图),废话不多说直接上代码: #import <UserNotifications/UserNotifications.h> - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for

  • iOS推送之本地通知UILocalNotification

    摘要: Notification是智能手机应用编程中非常常用的一种传递信息的机制,而且可以非常好的节省资源,不用消耗资源来不停地检查信息状态(Pooling),在iOS下应用分为两种不同的Notification种类,本地和远程.本地的Notification由iOS下NotificationManager统一管理,只需要将封装好的本地Notification对象加入到系统Notification管理机制队列中,系统会在指定的时间激发将本地Notification,应用只需设计好处理Notifi

  • iOS 引导页的镂空效果实例

    初衷 最近项目新功能更改较大,产品童鞋要求加入新功能引导,于是一口气花了两天的时间做了一个引导页,当然加上后面的修修补补的时间,就不只两天了,不过这事情其实是一劳永逸的事情,值得做.同时为了能够更好的复用,我把它做成了pod库,项目地址在这里:EAFeatureGuideView. EAFeatureGuideView能做什么 EAFeatureGuideView是UIView的一个扩展,用来做新功能引导提示,达到这样的效果: 局部区域高亮(可以设置圆角) 有箭头指向高亮区域 可以设置一段介绍文

  • iOS远程推送Push开发教程

    远程推送通知 什么是远程推送通知 顾名思义,就是从远程服务器推送给客户端的通知(需要联网)远程推送服务,又称为APNs(Apple Push Notification Services) 为什么需要远程推送通知 传统获取数据的局限性 只要用户关闭了app,就无法跟app的服务器沟通,无法从服务器上获得最新的数据内容 远程推送通知可以解决以上问题 不管用户打开还是关闭app,只要联网了,都能接收到服务器推送的远程通知 远程推送通知使用须知 所有的苹果设备,在联网状态下,都会与苹果的服务器建立长连接

  • iOS Remote Notification远程消息推送处理

    远程消息推送处理场景有三种:分别是app还没有运行.app在前台运行以及app在后台运行,下面介绍相关流程及三种场景下处理步骤 1.流程 (1)注册通知 首先是在注册远程消息推送,需要注意的是iOS8及以后的系统中注册方法有所改变(同时证书设置以及push权限也需要开启).这一步的目的是,允许app接收远程消息推送. (2)绑定deviceToken deviceToken相当于设备的一个标识,服务器根据这个标识来进行消息推送. ①当用户同意app接收远程消息推送后,手机会向APNs发起一个请求

  • iOS仿简书、淘宝等App的View弹出效果

    用简书App的时候觉得这个View的弹出效果特别好,而且非常平滑,所以我就尝试写了一个,和简书App上的效果基本一致了: 下面开始讲解: 1.首先我们要知道这个页面有几个View?这个页面其实有四个View,self.view , 图中白色VC的View rootVC.view ,白色VC上的maskView maskView , 以及弹出的popView popView .我们创建它们: self.view.backgroundColor = [UIColor blackColor]; _po

随机推荐