在iOS App中,如果要存储的数据量比较大,就会使用Core Data。这里汇总了下使用Core Data的基本方式。

  1. 添加Core Data
  2. 配置Core Data中的Entity
  3. 添加新数据
  4. 读取与修改数据
  5. 使用NSPredicate筛选数据
  6. 删除数据
  7. 保存数据
  8. 一份NSPredicate使用备忘清单

添加Core Data

如果在创建项目时没有勾选Using Core Data,可以手动创建Core Data。手动创建Core Data的方式如下:

  1. 在项目中创建新的文件,类型为:Core Data。
  2. 添加相关的预设方法进入AppDelegate中,相关方法如下:
func applicationWillTerminate(_ application: UIApplication) {
    self.saveContext()
}
	
// MARK: - Core Data stack
    
lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "DataModel")
    container.loadPersistentStores(completionHandler: { 
    (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()
    
// MARK: - Core Data Saving support
    
func saveContext () {
    let context = persistentContainer.viewContext
    if context.hasChanges {
        do {
            try context.save()
        } catch {
            let nserror = error as NSError
            fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
        }
    }
}

这两个方法是Xcode为使用Core Data的新项目自动创建的,我这里只是拷贝了进来。

配置Core Data中的Entity

点击创建的Core Data文件,我们在界面中配置Entity。Core Data中的Entity,就相当于编程语言中的Class,类比数据库就是一个Table。Entity的Attribute,就是Class的Property,Table中的Field。

举个例子: 我的To-do App中需要两个类,一个是Category,代表清单的类别;一个是Item,代表清单中的具体事项。

在Core Data中创建2个Entity分别是Category和Item。Category设置1个Attribute:name,类型为String;Item设置2个Attribute:title和done,分别是String和Bool类型。

然后配置Category和Item的关系,将Category对Item的关系设置为一对多,而Item对Category的关系设置为一对一,毕竟一个事项只有一个类别。

添加新数据

无论要对Core Data做什么,都需要用到context,因此需要在用到Core Data的类中添加一个实例变量:

let context = (UIApplication.shared.delegate
	as! AppDelegate).persistentContainer.viewContext

我要添加一个新的Category,那么从Core Data的Entity中创建对象是这样的:

let newCategory = Category(context: self.context)   // 用Core Data中的Entity创建对象

newCategory.name = "Work" // 设置Entity对象的必要attribute

// 将新的category对象加入categoryList,而categoryList则指向是从数据库中读取的数据。
categoryList.append(newCategory)  

读取与修改数据

从Core Data中读取全部数据:

func fetchData() {
    let request: NSFetchRequest<Category> = Category.fetchRequest()
    
    do {
    	// 将实例变量categoryList指向读取的数据
        categoryList = try context.fetch(request)  
    } catch {
        print("Error fetching request, \(error)")
    }
}

而要修改数据,则可以选择使用以下两种方式之一:

// 将刚加入的Work改为Shopping
categoryList[0].name = "Shopping" 

// 将刚才的Shopping category的name attribute改为"Chores"
categoryList[0].setValue("Chores", forKey: "name") 

使用Predicate筛选数据

有时我们不需要读取数据库中的所有数据,比如我只想读取:Category是Work的所有待办事项Item;或者我想搜索Work类别里待办事项中名字里包含"urgent"的事项,这时,我们这样写:

let selectedCategory = "Work"  // 清单类别
let searchKeyword = "urgent"  // 搜索筛选的关键词

let request: NSFetchRequest<Item> = Item.fetchRequest()

// 此处parentCategory是Core Data中Item的一个关系设定,将关系指向Category并命名为parentCategory。
let predicate1 = NSPredicate(format: "parentCategory.name MATCHES %@", selectedCategory) 

let predicate2 = NSPredicate(format: "title CONTAINS[cd] %@", searchKeyword)

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

request.predicate = compoundPredicate
request.sortDescriptors = [NSSortDescriptor(key: "title", ascending: true)]

do {
    self.selectedItems = try context.fetch(request)
} catch {
    print("Error fetching data, \(error)")
}       

删除数据

读取数据后,直接从指向数据的变量中,删除对应的数据即可。

self.context.delete(selectedItems[1]) // 从数据中移除
selectedItems.remove(at: 1) // 接着更新下指向数据的实例变量

保存数据

对Core Data进行新增、修改、删除后,都要进行保存才能生效。

do {
    try context.save()
} catch {
    print("Error saving data, \(error)")
}

NSPredicate使用备忘

关于Predicate的一份备忘清单,可以随时查看:NSPredicate备忘清单