@FetchRequest 中的 SwiftUI 和动态 NSSortDescriptors
Posted
技术标签:
【中文标题】@FetchRequest 中的 SwiftUI 和动态 NSSortDescriptors【英文标题】:SwiftUI and dynamic NSSortDescriptors in @FetchRequest 【发布时间】:2020-09-01 12:31:26 【问题描述】:我有一个包含标题和日期的项目列表。用户可以设置排序依据(标题或日期)。
但是我不知道如何动态更改 NSSortDescriptor。
import SwiftUI
import CoreData
struct ContentView: View
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Test.title, ascending: true)], animation: .default) private var items: FetchedResults<Test>
@State private var sortType: Int = 0
@State private var sortDescriptor: NSSortDescriptor = NSSortDescriptor(keyPath: \Test.title, ascending: true)
var body: some View
Picker(selection: $sortType, label: Text("Sort"))
Text("Title").tag(0)
Text("Date").tag(1)
.pickerStyle(SegmentedPickerStyle())
.onChange(of: sortType) value in
sortType = value
if sortType == 0
sortDescriptor = NSSortDescriptor(keyPath: \Test.title, ascending: true)
else
sortDescriptor = NSSortDescriptor(keyPath: \Test.date, ascending: true)
List
ForEach(items) item in
let dateString = itemFormatter.string(from: item.date!)
HStack
Text(item.title!)
Spacer()
Text(dateString)
.onAppear(perform:
if items.isEmpty
let newEntry1 = Test(context: self.viewContext)
newEntry1.title = "Apple"
newEntry1.date = Date(timeIntervalSince1970: 197200800)
let newEntry2 = Test(context: self.viewContext)
newEntry2.title = "Microsoft"
newEntry2.date = Date(timeIntervalSince1970: 168429600)
let newEntry3 = Test(context: self.viewContext)
newEntry3.title = "Google"
newEntry3.date = Date(timeIntervalSince1970: 904903200)
let newEntry4 = Test(context: self.viewContext)
newEntry4.title = "Amazon"
newEntry4.date = Date(timeIntervalSince1970: 773402400)
if self.viewContext.hasChanges
try? self.viewContext.save()
)
private let itemFormatter: DateFormatter =
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .none
return formatter
()
当我改变时
@FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Test.title, ascending: true)], animation: .default) private var items: FetchedResults<Test>
到
@FetchRequest(sortDescriptors: [sortDescriptor], animation: .default) private var items: FetchedResults<Test>
出现错误“不能在属性初始化器中使用实例成员'sortDescriptor';属性初始化器在'self'可用之前运行”。
我还尝试将 NSSortDescriptor 存储在 UserDefault 中并创建一个 init 来创建它自己的 FetchRequest.. 仍然没有动态排序...
有人指点在哪里寻找解决此问题的方法吗?
在这里找到整个项目:https://github.com/l1ghthouse/FRDSD
【问题讨论】:
在这个答案***.com/a/59345830/12299030 中考虑方法 - 它也适用于描述符。 @Asperi 是的,这行得通...非常感谢! 【参考方案1】:解决了!感谢 Asperi 指出这个 QA:https://***.com/a/59345830/12299030
import SwiftUI
import CoreData
struct ContentView: View
@Environment(\.managedObjectContext) private var viewContext
@AppStorage("firstLaunch") var firstLaunch: Bool = true
@State var sortDescriptor: NSSortDescriptor = NSSortDescriptor(keyPath: \Test.title, ascending: true)
@State private var sortType: Int = 0
var body: some View
Picker(selection: $sortType, label: Text("Sort"))
Text("Title").tag(0)
Text("Date").tag(1)
.pickerStyle(SegmentedPickerStyle())
.onChange(of: sortType) value in
sortType = value
if sortType == 0
sortDescriptor = NSSortDescriptor(keyPath: \Test.title, ascending: true)
else
sortDescriptor = NSSortDescriptor(keyPath: \Test.date, ascending: true)
ListView(sortDescripter: sortDescriptor)
.onAppear(perform:
if firstLaunch == true
let newEntry1 = Test(context: self.viewContext)
newEntry1.title = "Apple"
newEntry1.date = Date(timeIntervalSince1970: 197200800)
let newEntry2 = Test(context: self.viewContext)
newEntry2.title = "Microsoft"
newEntry2.date = Date(timeIntervalSince1970: 168429600)
let newEntry3 = Test(context: self.viewContext)
newEntry3.title = "Google"
newEntry3.date = Date(timeIntervalSince1970: 904903200)
let newEntry4 = Test(context: self.viewContext)
newEntry4.title = "Amazon"
newEntry4.date = Date(timeIntervalSince1970: 773402400)
if self.viewContext.hasChanges
try? self.viewContext.save()
firstLaunch = false
)
struct ListView: View
@FetchRequest var items: FetchedResults<Test>
@Environment(\.managedObjectContext) var viewContext
init(sortDescripter: NSSortDescriptor)
let request: NSFetchRequest<Test> = Test.fetchRequest()
request.sortDescriptors = [sortDescripter]
_items = FetchRequest<Test>(fetchRequest: request)
var body: some View
List
ForEach(items) item in
let dateString = itemFormatter.string(from: item.date!)
HStack
Text(item.title!)
Spacer()
Text(dateString)
private let itemFormatter: DateFormatter =
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .none
return formatter
()
【讨论】:
你能让动画在这个上工作吗?当我排序时,整个列表视图被重新创建并且没有重新排序动画。以上是关于@FetchRequest 中的 SwiftUI 和动态 NSSortDescriptors的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SwiftUI 中限制 FetchRequest 中的结果数
当SwiftUI中的相关实体发生变化时,如何更新@FetchRequest?
在@FetchRequest 中输入一个动态值,以从 SwiftUI 中的核心数据中获取单个实体
SwiftUI - 使用 @ObservedObject 作为同一结构中 @FetchRequest 的结果来强制更新 UI
SwiftUI:Core Data @FetchRequest 和 List 显示托管对象 - 在 lockscreemn 上丢失数据