由于关系是集合,我在 SwiftUI 中显示我的核心数据时遇到了问题。在 SwiftUI ForEach 循环中显示多个关系集的最佳方法是什么?
例如,我在核心日期中有两个实体:Entry & Position。条目可以包含多个位置,每个位置只能属于一个条目。
我在应该显示条目位置的 View 上将条目作为@binding var。理想情况下,我希望直接从此条目变量访问位置,但由于位置是一个集合,我收到以下错误:
错误“ForEach”要求“Set”符合“RandomAccessCollection”
@Binding private var entry: Entry?
ForEach(entry?.positions) { position in
Text("position here")
}
解决方案一:
或者,我可以对所有职位进行获取请求,然后过滤掉所有不属于实体的职位,我不喜欢这个想法,因为我可能会获取数千个职位而只获得几个职位。 (或者我想错了吗?我是核心数据的新手,因为 swiftui 而来自领域)
虽然如果我只能在@binding entry var上进行提取,并将其所有位置作为排序的提取结果提取,这可能会起作用,但我不确定是否有办法做到这一点。
也许像这样,或者如果可能有数千个条目,每个条目都有 10-20 多个位置,这会是一个性能问题吗? objectID 可以这样使用吗,如果条目被移到另一个期刊,它仍然是唯一的吗?:
@Binding private var entry: Entry?
@FetchRequest(
entity: Position.entity(),
sortDescriptors: [],
predicate: NSPredicate(formate: "entry.objectID == %@", self.entry.objectID)
) var positions: FetchedResults<Position>
解决方案二:
我想为诸如“日期”之类的位置添加一个属性,这样可以比较和排序位置吗?但不确定如何使用 SwiftUI 进行更新,因为它只会在 init() 中完成一次。
let list = entry.wrappedValue?.positions?.sorted()
核心数据模型:
public class Entry: NSManagedObject, Identifiable {
// MARK: - ATTRIBUTES
@NSManaged public var date: Date
// MARK: - RELATIONSHIPS
@NSManaged public var journal: Journal?
@NSManaged public var positions: Set<Position>?
}
public class Position: NSManagedObject, Identifiable {
// MARK: - RELATIONSHIPS
@NSManaged public var entry: Entry?
}
你将如何解决这个问题?请记住,在列出位置的 View 上,该 View 可以添加、删除和修改位置,因此解决方案应该允许 SwiftUI 在进行更改时重新加载 View 并更新位置。
最佳答案
@JoakimDanielson 评论就像一个魅力,但需要一些调整。
在数组初始值设定项中包装集合的工作方式如下,但需要解开可选集合。我惊讶地发现即使设置为零,强制展开也不会导致崩溃?也许有人可以解释一下?
ForEach(Array(entry.positions!)) { position in
Text("Position")
}
下一个问题是,每次由于集合无序而导致位置集合发生变化时,数组都会被随机化。因此,通过使 Position 符合 Comparable Protocol 解决了这个问题。我认为按日期对位置进行排序最有意义,所以我更新了模型,如下所示:
public class Position: NSManagedObject, Identifiable {
// MARK: - ATTRIBUTES
@NSManaged public var date: Date
// MARK: - RELATIONSHIPS
@NSManaged public var entry: Entry?
}
extension Position: Comparable {
static func < (lhs: Position, rhs: Position) -> Bool {
lhs.date < rhs.date
}
}
然后可以对 ForEach 进行排序,如下所示:
ForEach(Array(entry.positions!).sorted()) { position in
Text("\(position.date)")
}
我发现了一些其他解决方案,但由于原始帖子中提到的原因并不理想,但它们确实有效,是使用在 View 初始化中自定义的获取请求,如下所示:
@FetchRequest var positions: FetchedResults<Position>
init(entry: Entry) {
var predicate: NSPredicate?
// Do some kind of control flow for customizing the predicate here.
predicate = NSPredicate(formate: "entry == %@", entry)
self._positions = FetchRequest(
entity: Position.entity(),
sortDescriptors: [],
predicate: predicate
)
}
或者创建一个绑定(bind)到@ObservedObject 的“中间人” View 模型,它将核心数据托管对象转换为可用的 View 数据。对我来说,这最没有意义,因为它基本上包含一堆已经在核心数据托管对象中找到的冗余信息,而且我喜欢核心数据托管对象也是单一事实来源的想法。
关于swift - 如何在 ForEach SwiftUI 中使用核心数据关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58739719/