今天要學(xué)習(xí)的是如何在SwiftUI中使用CoreData宫仗。
知識點(diǎn):
1吩抓、已有項(xiàng)目添加CoreData
2、SwiftUI中處理CoreData中的entity锌俱,包括讀取炭臭,添加永脓,刪除
3、SwiftUI中保存并讀取環(huán)境變量
學(xué)習(xí)鏈接來自該篇文章鞋仍,講的很細(xì)
CoreData
什么是CoreData常摧?它有什么作用?它的優(yōu)勢威创?網(wǎng)上有很多相關(guān)資料落午,這里就不多說了谎懦。可以大致的看下如下總體結(jié)構(gòu)圖 引用自該文章
-
已有項(xiàng)目添加CoreData
添加CoreData方式有二板甘,一是新創(chuàng)建項(xiàng)目時(shí)党瓮,勾選CoreData盐类,創(chuàng)建完項(xiàng)目后,自動添加了涉及的相關(guān)功能呛谜。二就是下面要說的在跳,如何在已有的項(xiàng)目添加CoreData,主要分下面三步:
1隐岛、手動創(chuàng)建xcdatamodeld文件猫妙,文件名稱一般命名工程名稱
2、在SeneDelegate.swift里添加相應(yīng)代碼聚凹。其實(shí)就是創(chuàng)建并設(shè)置container割坠。
func sceneDidEnterBackground(_ scene: UIScene) {
saveContext()
}
//MARK: -CoreData
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "CoredataSwiftUI")
container.loadPersistentStores { _, error in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}
return container
}()
func saveContext() {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let error = error as NSError
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}
}
3、打開xcdatamodeld文件妒牙,添加相應(yīng)的model也就是entity彼哼。這里我們創(chuàng)建Movie模型
SwiftUI使用CoreData
- 設(shè)置根視圖CoreData viewContext.如下代碼
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let context = persistentContainer.viewContext
let contentView = MovieList().environment(\.managedObjectContext, context)
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.rootViewController = UIHostingController(rootView: contentView)
window?.makeKeyAndVisible()
}
- 通過讀取環(huán)境變量中的CoreData viewContext,執(zhí)行后續(xù)添加/刪除保存湘今。這里有個(gè)疑問點(diǎn) 在讀取Movie對象的時(shí)候敢朱,沒有告訴到底是哪個(gè)container,難道一個(gè)工程下就只能存在一個(gè)container摩瞎?拴签??核心代碼如下旗们,注意看注釋
import SwiftUI
struct MovieList: View {
// 讀取viewContext蚓哩,賦值給managedObjectContext屬性
@Environment(\.managedObjectContext) var managedObjectContext
// 讀取Movie對象集,賦值給movies數(shù)組上渴。沒有要求傳入任何name
@FetchRequest(entity: Movie.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Movie.title, ascending: true)]) var movies: FetchedResults<Movie>
@State var isPresented = false
var body: some View {
NavigationView {
List {
ForEach(movies, id: \.title) {
MovieRow(movie: $0)
}
.onDelete(perform: deleteMovie)
}
.sheet(isPresented: $isPresented) {
AddMovieView { title, genre, release in
self.addMovie(title: title, genre: genre, releaseDate: release)
self.isPresented = false
}
}
.navigationBarTitle(Text("Fave Flicks"))
.navigationBarItems(trailing:
Button(action: { self.isPresented.toggle() }) {
Image(systemName: "plus")
}
)
}
}
// 刪除一個(gè)movie岸梨,并更新coredata數(shù)據(jù)庫
func deleteMovie(at offsets: IndexSet) {
// 1.
offsets.forEach { index in
// 2.
let movie = self.movies[index]
// 3.
self.managedObjectContext.delete(movie)
}
// 4.
saveContext()
}
// 添加一個(gè)movie,并更新保存數(shù)據(jù)庫
func addMovie(title: String, genre: String, releaseDate: Date) {
// 1 從viewContext獲取一個(gè)Movie對象
let newMovie = Movie(context: managedObjectContext)
// 2
newMovie.title = title
newMovie.genre = genre
newMovie.releaseDate = releaseDate
// 3
saveContext()
}
func saveContext() {
do {
try managedObjectContext.save()
} catch {
print("Error saving managed object context: \(error)")
}
}
}
SwiftUI中使用CoreData驰贷,總結(jié)幾個(gè)點(diǎn)
1盛嘿、如何將內(nèi)存中管理coredata的persistentContainer.viewContext
傳給相應(yīng)的view。當(dāng)然在非SwiftUI項(xiàng)目中括袒,可能直接在AppDelegate定義成相應(yīng)的熟悉次兆,之后用的地方通過AppDelegate獲取即可
2、SwiftUI view中如何獲取viewContext锹锰,繼而通過viewContext處理添加或刪除并保存更新操作
3芥炭、如何讀取coredata里面相應(yīng)的entity
SwiftUI中保存并讀取環(huán)境變量
從上面的代碼漓库,很容易發(fā)現(xiàn)SwiftUI中是如何保存并讀取環(huán)境變量的。
保存設(shè)置環(huán)境變量:
SceneDelegate.swift文件
let context = persistentContainer.viewContext
let contentView = MovieList().environment(\.managedObjectContext, context)
從當(dāng)前環(huán)境中讀取變量:
MovieList.swift文件
// 讀取viewContext园蝠,賦值給managedObjectContext屬性
@Environment(\.managedObjectContext) var managedObjectContext
End
- 還記的上面那個(gè)疑問點(diǎn)嗎渺蒿?
疑問點(diǎn) 在讀取Movie對象的時(shí)候,沒有告訴到底是哪個(gè)container彪薛,難道一個(gè)工程下就只能存在一個(gè)container茂装??善延?
查看官方文檔找到了答案:
如上步驟搜索NSFetchRequest
會發(fā)現(xiàn)這么一段話少态,當(dāng)然你還會發(fā)現(xiàn)其它讀取entity時(shí)的一些重要設(shè)置,如從什么地方開始讀易遣,最大讀多少彼妻,應(yīng)該讀哪個(gè)store,返回哪些數(shù)據(jù)等
對于移動端中小型項(xiàng)目來說一個(gè)是container豆茫,已經(jīng)夠用侨歉,也建議用一個(gè)。對于多個(gè)數(shù)據(jù)庫container使用場景揩魂,目前還沒接觸到幽邓。
-
如何避免讀取重復(fù)的數(shù)據(jù)呢? 例如肤京,一個(gè)學(xué)生列表中有很多同名的學(xué)生 分?jǐn)?shù)可能不同颊艳,現(xiàn)在不需要重復(fù)讀取多個(gè)同名學(xué)生信息。如下2步設(shè)置即可
1忘分、改動xcdatamodeld文件
約束name屬性不重名
2棋枕、代碼里設(shè)置viewContext
參考該篇文章,解析很詳細(xì)妒峦,以及hash的介紹
-
CoreData常用的幾個(gè)謂詞重斑,即篩選器