【问题标题】:How to use Core Data Relationship in ForEach SwiftUI如何在 ForEach SwiftUI 中使用核心数据关系
【发布时间】:2020-03-03 12:02:55
【问题描述】:

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

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

我将条目作为@binding var 在应该显示条目位置的视图上。理想情况下,我希望直接从此条目变量访问位置,但由于位置是一个集合,我收到以下错误:

错误 'ForEach' 要求 'Set' 符合 '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 在进行更改时重新加载视图并更新位置。

【问题讨论】:

  • 我也有同样的问题。如果您找到解决方案,请发布答案。
  • 你试过ForEach(Array(entry?.positions))吗?
  • @JoakimDanielson 非常简单。虽然可选需要强制展开,但令我惊讶的是,即使条目内没有位置,这也不会导致崩溃ForEach(Array(entry.positions!))...副作用是数组每次更改时都会以随机顺序排列,所以这与符合 Comparable 协议的职位配对就像一​​个魅力。谢谢!
  • 您可以根据需要添加排序...
  • 对,符合 Comparable 允许ForEach(Array(entry.positions!).sorted())

标签: swift core-data swiftui


【解决方案1】:

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

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

@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 的“中间人”视图模型,将核心数据托管对象转换为可用的视图数据。对我来说,这最没有意义,因为它基本上包含一堆已经在核心数据托管对象中找到的冗余信息,而且我喜欢核心数据托管对象也是单一事实来源的想法。

【讨论】:

  • 使用 Comparable 的一个选项是使用闭包进行排序,如果 date 不是该类的自然排序顺序,它可能是一个不错的选择。 .sorted(by: { $0.date &lt; $1.date })
  • 我明白了,很高兴知道。但在这种情况下,日期确实很有意义。再次感谢您!
  • 您也可以发布您的代码以进行添加/编辑等吗?我需要学习如何添加和编辑关系。
  • 我尝试了上述解决方案的每个版本,但收到了各种错误。对于@FetchRequest 的第二部分,我收到“从初始化程序返回而不初始化所有存储的属性”。
  • 是的,这个解决方案不起作用。位置作为 NSSet 而不是位置返回。代码编译但尝试访问位置上的任何属性,编译器会告诉你它是一个 NSSet
【解决方案2】:

只需将自定义的FetchRequest 参数传递给包含@FetchRequest 属性包装器的视图。

struct PositionsView: View {

    let entry: Entry

    var body: some View {
        PositionsList(positions: FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Positions.date, ascending: true)], predicate: NSPredicate(format: "entry = %@", entry)))
    }
}

struct PositionsList : View {

    @FetchRequest var positions: FetchedResults<Positions>

    var body: some View {
        ForEach(positions) { position in
             Text("\(position.date!, formatter: positionFormatter)")
        }
    }
}

有关更多详细信息,请参阅此answer

【讨论】:

    猜你喜欢
    • 2022-10-13
    • 2020-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多