Swift使用CoreData时遇到的一些填坑记录

时间:2022-09-20 18:53:31

前言

最近在做一个 App 练手,其中用到了 CoreData 来存储用户的播放列表,由于 CoreData 这部分的文章还是比较少的,所以遇到了不少坑,所以写篇随笔记录一下。

题外话:可以给大家看看这个 App 的界面,我觉得还是挺清新的😄

Swift使用CoreData时遇到的一些填坑记录

P.S. 作为背景的氛围图片用的是 CoreImage 生成的

切入正题。

#0 何时执行保存

起初我认为不用显式执行 Xcode 给我们在 AppDelegate 中生成的 saveContext 函数,因为默认情况下 applicationWillTerminate 会执行 saveContext,但是我发现这个生命周期函数压根不靠谱,当用户直接从多任务视图将 App 结束掉时这个函数根本来不及执行完毕,导致我们的数据不能及时写入本地数据库中。所以合理的调用时机我认为还是应该在完成一批操作以后就直接执行一次 saveContext

下面简单贴一下我的部分代码吧:

Swift使用CoreData时遇到的一些填坑记录

Swift使用CoreData时遇到的一些填坑记录

#1 Relationships 到底什么鬼

另外一个让我很头疼的就是 Relationships,写这块的那天可能有点情绪原因,看苹果官方的 Guideline 看不进去,而且 Google 关于 Relationships 相关的文章也十分少,索性自己闷头研究了。

先说说我遇到了什么问题,我想将属于一个歌单的所有 Song 实体添加到 Playlist 实体的 songs 这个 Relationships 中去,但是发现怎么加都加不进去。我已开始的做法是先用 valueForKey 拿到 songs 属性所代表的 NSManagedObject,然后强制转换到 NSMutableSet 然后执行添加操作,发现人家压根不鸟我这个操作,虽然没有抛异常,也没有任何 log 打出,但是 “It does NOT work!!!”。

经过一番研究,我发现了 NSManagedObject 有个 mutableSetValueForKey,才发现当初我真是傻了逼了....

于是用 mutableSetValueForKey 拿到这个 NSMutableSet 顺利执行添加操作并保存,成功了。

#2 Type Conversion From Objective-C to Swift

这块主要是谈谈一些关于类型的一些事。我们知道 Swift 引入了一系列新的数据类型,比如 String、Int、Dictionary、Array,还有一个神奇的 AnyObject 和 Optional<T> 值。

这里我就直接说了

Swift 中的 String 可以直接作为 NSString 使用,它们之间可以 Toll-Free 转换
Int、Float、Double 仍然不是一个标准的 NSObject 对象,所以 KVC 就没有它们什么事,所以我们仍然需要用 NSNumber 包装一下送入 NSManagedObject,同时拿出来的时候用 xxxValue 取出。

还有,Relationships 一定是 NSSet 类型,不是 NSArray 类型,数据库的关系都是无序的,如果需要有序可以添加一个字段然后查询时用 SortDescription 来排序。

最后,"!"是邪恶符号,慎用。

CoreData在Swift 3.0中的一点改变

在Swift 2.0中我们需要从core data中query结果的时候使用的是如下方式:

?
1
2
3
4
5
6
7
8
9
10
11
func findAnimals() {
let request = NSFetchRequest(entityName:”Animal")
do {
guard let searchResults = try context.executeFetchRequest(request) as? [Animal] else {
print("Results were not of the expected structure")
}
... use(searchResults) ...
} catch {
print("Error ocurred during execution: \(error)")
}
}

注意:以上代码试图将executeFetchRequest返回的结果转换为实际数据类型的数组。同时我们看到,在建立request的时候直接使用的是NSFetchRequest的纯构造器方式。

但是在Swift 3.0中首先我们在创建request的时候必须用范型来指定实际数据类型,你可以用如下任何一句来完成:

?
1
2
3
let fetch0 = NSFetchRequest<Commit>(entityName: "Commit")
 
let fetch1:NSFetchRequest<Commit> = Commit.fetchRequest()

接下来在处理fetch结果的时候我们不可以将NSFetchRequestResult直接转换为[Commit],因为这样非相关性的转换总是失败!作为代替我们使用context的另一个方法来完成:

?
1
2
3
4
5
6
7
8
9
do{
let commits = try managedObjectContext.fetch(fetch)
print("***** \(commits.count) commits *****")
objects = commits
tableView.reloadData()
 
}catch let error{
print("Fetch failed : \(error.localizedDescription)")
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:http://www.jianshu.com/p/ddc1a0b227a6