版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2020.05.30 星期六 |
前言
數(shù)據(jù)的持久化存儲(chǔ)是移動(dòng)端不可避免的一個(gè)問題,很多時(shí)候的業(yè)務(wù)邏輯都需要我們進(jìn)行本地化存儲(chǔ)解決和完成彻磁,我們可以采用很多持久化存儲(chǔ)方案,比如說
plist
文件(屬性列表)沥潭、preference
(偏好設(shè)置)驻仅、NSKeyedArchiver
(歸檔)、SQLite 3
谱煤、CoreData
,這里基本上我們都用過禽拔。這幾種方案各有優(yōu)缺點(diǎn)刘离,其中,CoreData是蘋果極力推薦我們使用的一種方式睹栖,我已經(jīng)將它分離出去一個(gè)專題進(jìn)行說明講解硫惕。這個(gè)專題主要就是針對(duì)另外幾種數(shù)據(jù)持久化存儲(chǔ)方案而設(shè)立。
1. 數(shù)據(jù)持久化方案解析(一) —— 一個(gè)簡(jiǎn)單的基于SQLite持久化方案示例(一)
2. 數(shù)據(jù)持久化方案解析(二) —— 一個(gè)簡(jiǎn)單的基于SQLite持久化方案示例(二)
3. 數(shù)據(jù)持久化方案解析(三) —— 基于NSCoding的持久化存儲(chǔ)(一)
4. 數(shù)據(jù)持久化方案解析(四) —— 基于NSCoding的持久化存儲(chǔ)(二)
5. 數(shù)據(jù)持久化方案解析(五) —— 基于Realm的持久化存儲(chǔ)(一)
6. 數(shù)據(jù)持久化方案解析(六) —— 基于Realm的持久化存儲(chǔ)(二)
7. 數(shù)據(jù)持久化方案解析(七) —— 基于Realm的持久化存儲(chǔ)(三)
8. 數(shù)據(jù)持久化方案解析(八) —— UIDocument的數(shù)據(jù)存儲(chǔ)(一)
9. 數(shù)據(jù)持久化方案解析(九) —— UIDocument的數(shù)據(jù)存儲(chǔ)(二)
10. 數(shù)據(jù)持久化方案解析(十) —— UIDocument的數(shù)據(jù)存儲(chǔ)(三)
11. 數(shù)據(jù)持久化方案解析(十一) —— 基于Core Data 和 SwiftUI的數(shù)據(jù)存儲(chǔ)示例(一)
源碼
1. Swift
首先看下工程組織結(jié)構(gòu)
下面就是源碼了
1. AddMovie.swift
import SwiftUI
struct AddMovie: View {
static let DefaultMovieTitle = "An untitled masterpiece"
static let DefaultMovieGenre = "Genre-buster"
@State var title = ""
@State var genre = ""
@State var releaseDate = Date()
let onComplete: (String, String, Date) -> Void
var body: some View {
NavigationView {
Form {
Section(header: Text("Title")) {
TextField("Title", text: $title)
}
Section(header: Text("Genre")) {
TextField("Genre", text: $genre)
}
Section {
DatePicker(
selection: $releaseDate,
displayedComponents: .date) {
Text("Release Date").foregroundColor(Color(.gray))
}
}
Section {
Button(action: addMoveAction) {
Text("Add Movie")
}
}
}
.navigationBarTitle(Text("Add Movie"), displayMode: .inline)
}
}
private func addMoveAction() {
onComplete(
title.isEmpty ? AddMovie.DefaultMovieTitle : title,
genre.isEmpty ? AddMovie.DefaultMovieGenre : genre,
releaseDate)
}
}
2. MovieList.swift
import SwiftUI
// swiftlint:disable multiple_closures_with_trailing_closure
struct MovieList: View {
@Environment(\.managedObjectContext) var managedObjectContext
// 1.
@FetchRequest(
// 2.
entity: Movie.entity(),
// 3.
sortDescriptors: [
NSSortDescriptor(keyPath: \Movie.title, ascending: true)
]
//,predicate: NSPredicate(format: "genre contains 'Action'")
// 4.
) 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) {
AddMovie { 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")
}
)
}
}
func deleteMovie(at offsets: IndexSet) {
// 1.
offsets.forEach { index in
// 2.
let movie = self.movies[index]
// 3.
self.managedObjectContext.delete(movie)
}
// 4.
saveContext()
}
func addMovie(title: String, genre: String, releaseDate: Date) {
// 1
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)")
}
}
}
struct MovieList_Previews: PreviewProvider {
static var previews: some View {
MovieList()
}
}
3. MovieRow.swift
import SwiftUI
struct MovieRow: View {
let movie: Movie
static let releaseFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .long
return formatter
}()
var body: some View {
VStack(alignment: .leading) {
movie.title.map(Text.init)
.font(.title)
HStack {
movie.genre.map(Text.init)
.font(.caption)
Spacer()
movie.releaseDate.map { Text(Self.releaseFormatter.string(from: $0)) }
.font(.caption)
}
}
}
}
4. AppDelegate.swift
import SwiftUI
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
// MARK: UISceneSession Lifecycle
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
return UISceneConfiguration(
name: "Default Configuration",
sessionRole: connectingSceneSession.role)
}
}
5. SceneDelegate.swift
import SwiftUI
import CoreData
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
let context = persistentContainer.viewContext
let contentView = MovieList().environment(\.managedObjectContext, context)
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
func sceneDidEnterBackground(_ scene: UIScene) {
saveContext()
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "FaveFlicks")
container.loadPersistentStores { _, error in
if let error = error as NSError? {
// You should add your own error handling code here.
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 {
// The context couldn't be saved.
// You should add your own error handling here.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
后記
本篇主要講述了基于Core Data 和 SwiftUI的數(shù)據(jù)存儲(chǔ)示例野来,感興趣的給個(gè)贊或者關(guān)注~~~