Как использовать Core Data Relationship в ForEach SwiftUI - PullRequest
2 голосов
/ 07 ноября 2019

У меня возникли проблемы с отображением моих базовых данных в SwiftUI из-за отношений между наборами. Каков наилучший способ отображения множества отношений внутри цикла SwiftUI ForEach?

Например, у меня есть две сущности в базовой дате: Entry & Position. Запись может содержать много позиций, и каждая позиция может принадлежать только одной записи.

У меня есть запись как переменная @binding в представлении, которое должно отображать позиции записи. В идеале я хотел бы получить доступ к позициям непосредственно из этой входной переменной, но поскольку позиции являются множеством, я получаю следующую ошибку:

Ошибка «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 перезагружать представление и обновлять позиции после внесения изменений.

1 Ответ

0 голосов
/ 07 ноября 2019

@ Комментарий JoakimDanielson работает как шарм, но требует нескольких настроек.

Обтекание набора в инициализаторе массива работает следующим образом, но требует развертывания необязательных наборов. Я был удивлен, обнаружив, что принудительное развертывание не вызывает сбой, даже если набор равен нулю? Может быть, кто-то может объяснить это?

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

, либо создать "середину"man "Модель представления, связанная с @ObservedObject, которая преобразует управляемые объекты основных данных в полезные данные представления. Что для меня не имеет смысла, потому что оно будет содержать кучу избыточной информации, уже найденной в управляемом объекте основных данных, и мне нравится идея, что управляемый объект основных данных также является единственным источником правды.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...