如何以关系对象作为其节id来获取SectionedFetchRequest

问题描述 投票:0回答:1

我的应用程序中有两个实体,“Card”和“CardRecord”,它们具有 1:n 关系,一张卡有很多记录。我有一个视图需要显示每张卡中有多少条记录,所以这是我的代码:

@SectionedFetchRequest
private var sectionRecords: SectionedFetchResults<Card, CardRecord>

init(month: Int32) {
    let predicate = NSPredicate(format: "month = %i", month)
    _sectionRecords = SectionedFetchRequest<Card, CardRecord>(
        entity: CardRecord.entity(),
        sectionIdentifier: \CardRecord.card!,
        sortDescriptors: [],
        predicate: predicate
    )
}

var body: some View {
    VStack(alignment: .leading) {
        ForEach(sectionRecords) { section in
            CardExpansionView(card: section.id, num: Int32(section.count))
        }
    }
}

我只需要循环sectionRecords,因为我只需要每个部分的编号,并且我需要显示@ObservedObjectCard,这就是为什么我使用关系对象Card作为部分id。

当我在模拟器中运行应用程序时,出现错误:

ForEach<SectionedFetchResults<Card, CardRecord>, Card, CardExpansionView>: the ID <Card: 0x6000025fdf40> (entity: Card; id: 0xe565b4b98e84a111 <x-coredata://292B0160-058F-48AE-BFCC-11196BF00552/Card/p24>; data: {
    cid = "6E3C25B7-2DC2-4538-B3D9-950A387C13AD";
    color = CardBrown;
    createTime = "2024-04-04 07:47:22 +0000";
    icon = "cup.and.saucer";
    name = "NO COFFEE";
    records = "<relationship fault: 0x60000063f6e0 'records'>";
}) occurs multiple times within the collection, this will give undefined results!

同时又出现了一个问题,页面显示的节数不正确,并且有重复的卡片。

然后我在实体“CardRecord”中添加属性“cardId”,并将sectionid更改为cardId

sectionIdentifier: \CardRecord.cardId!

当我再次运行该应用程序时...错误消失了,但是部分的数量仍然错误并且重复仍然存在。

那么,问题是什么以及我需要做什么。

最后,一个问题:如何通过“section.count”对“sectionRecords”进行排序

谢谢。

swiftui core-data
1个回答
0
投票
var body: some View {
        
    VStack(alignment: .leading) {
        ForEach(ranksFetcher.ranks, id: \.id) { rank in
            CardExpansionView(card: rank.card, num: rank.count, maxWidth: rank.width)
        }
    }
    .frame(maxWidth: .infinity, alignment: .leading)
    .onAppear() {
        if fetch {
            ranksFetcher.moc = moc
            ranksFetcher.maxWidth = viewWidth()
            ranksFetcher.fetch(yearmonth: yearmonth)
            fetch.toggle()
        }
    }
}
class RanksFetcher: NSObject, ObservableObject {
    var moc: NSManagedObjectContext?
    var maxWidth: CGFloat?
    
    @Published
    private(set) var ranks: [CardRankModel] = []
    
    func fetch(yearmonth: Int32) {
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "CardRecord")
        fetchRequest.predicate = NSPredicate(format: "month = %i", yearmonth)
        fetchRequest.propertiesToGroupBy = ["cardId"]
        fetchRequest.resultType = .dictionaryResultType
        
        // Defining column 'count'
        let expressDescription = NSExpressionDescription()
        expressDescription.resultType = .integer32
        let name = "count"
        expressDescription.name = name
        
        // Count witch column
        let cardId = NSExpression(forKeyPath: \CardRecord.cardId)
        let express = NSExpression(forFunction: "count:", arguments: [cardId])
        expressDescription.expression = express
        fetchRequest.propertiesToFetch = ["cardId", expressDescription]
        
        var groups = (try? moc!.fetch(fetchRequest) as? [[String: Any]]) ?? []
        groups.sort { e1, e2 in
            let i1 = e1["count"] as? Int32 ?? 0
            let i2 = e2["count"] as? Int32 ?? 0
            return i1 > i2
        }
        
        var cardIds = [String]()
        for gp in groups {
            cardIds.append(gp["cardId"] as! String)
        }
        
        let cardsFetchRequest = NSFetchRequest<Card>(entityName: "Card")
        cardsFetchRequest.predicate = NSPredicate(format: "cid in (%@)", cardIds)
        let cards = (try? moc!.fetch(cardsFetchRequest)) ?? []
        let cardMap = Dictionary.init(cards.map { ($0.cid, $0) }) { $1 }
        let maxWidth = maxWidth!
        let maxCount = groups.first?["count"] as? Int32
        
        var data: [CardRankModel] = []
        for gp in groups {
            let cardId = gp["cardId"] as! String
            let count = gp["count"] as? Int32 ?? 0
            if let card = cardMap[cardId] {
                let cardRankModel = CardRankModel(id: card.cid!, card: card, count: count, width: maxWidth * (CGFloat(count) / CGFloat(maxCount!)))
                data.append(cardRankModel)
            }
        }
        
        ranks = data
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.