如何在ForEach SwiftUI中使用核心数据关系

由于设置了关系,我在SwiftUI中显示我的核心数据时遇到了问题。在SwiftUI ForEach循环中显示多个关系集的最佳方法是什么?

例如,我在核心日期有两个实体:“入职”和“职位”。条目可以包含多个职位,每个职位只能属于一个条目。

我在视图上将Entry作为@binding var假设是要显示条目的Positions。理想情况下,我想直接从此输入变量访问位置,但是由于位置是Set,因此出现以下错误:

错误“ ForEach”要求“设置”符合“ RandomaccessCollection”

@Binding private var entry: Entry?

ForEach(entry?.positions) { position in
    Text("position here")
}

解决方案一:

或者,我可以对所有职位进行提取请求,然后过滤掉所有不属于该实体的职位,我不喜欢这个想法,因为我可能会获取数千个职位,但只能得到几个职位。 (或者我在想这个错误吗?我是核心数据的新手,由于swiftui而来自领域)

尽管如果我只能在@binding条目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?
}

您将如何解决这个问题?请记住要列出位置的视图,该视图可以添加,删除和修改位置,因此该解决方案应允许SwiftUI重新加载视图并在进行更改时更新位置。

talang2009 回答:如何在ForEach SwiftUI中使用核心数据关系

@JoakimDanielson的评论就像一个咒语,但需要一些调整。

在数组初始化程序中包装集合的工作原理是这样的,但是需要将可选的集合解开。我很惊讶地发现即使将其设置为nil,强制展开也不会导致崩溃?也许有人可以解释一下?

ForEach(Array(entry.positions!)) { position in
   Text("Position")
}

下一个问题是,由于位置无序,因此每次位置变化都会使数组随机化。因此,通过使位置符合可比协议可以解决此问题。我认为按日期对位置进行排序最有意义,因此我像这样更新了模型:

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)")
}

我发现了一些其他解决方案,但由于原始帖子中提到的原因而并不理想,但它们确实起作用,它们是使用在视图init内自定义的获取请求,如下所示:

@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
    )
}

或创建绑定到@ObservedObject的“中间人”视图模型,该模型将核心数据托管对象转换为可用的视图数据。在我看来,这是最没有意义的,因为它基本上将包含一堆已经在核心数据托管对象中找到的冗余信息,并且我喜欢核心数据托管对象也是唯一的事实来源的想法。

,

在获取请求中使用排序描述符。

这是Core Data的新提示。设计模型,以显示UI的显示方式,而不是像数据库规范化那样。

本文链接:https://www.f2er.com/3148439.html

大家都在问