1

我似乎陷入了 Catch-22 的情况。也许我的方法在这里完全错误。我希望有人能帮帮忙。我想使用访问特定现实世界地标的用户的反馈创建基于星级的评级显示。在 CoreData 中,我有一个名为 Rating 的实体,其属性名为 rating (Int32) 和 landmark (String)。我想获得与给定地标相关的所有评级的平均值,以便在每个评级的视图中显示星星。这是视图的代码:

struct TitleImageView: View {
    @Environment(\.managedObjectContext) var viewContext : NSManagedObjectContext
    let landmark: Landmark 
    var body: some View {
        
        Image(landmark.imageName)
            .resizable()
            .shadow(radius: 10 )
            .border(Color.white)
            .scaledToFit()
            .padding([.leading, .trailing], 40)
            .layoutPriority(1)
            .overlay(TextOverlay(landmark: landmark))
            .overlay(RatingsOverlay(rating: stars))
    }
}

这是 fetch(当 fetch 的参数被硬编码时,它按预期工作):

let fetchRequest = Rating.fetchRequestForLandmark(landmark: landmark.name)
    var ratings: FetchedResults<Rating> {
            fetchRequest.wrappedValue
    }
        var sum: Int32 {
            ratings.map { $0.rating }.reduce(0, +)
        }
        var stars : Int32 {
            sum / Int32(ratings.count)
        } 

问题是这样的:当我在视图主体之前插入 fetch 时,我收到警告

“不能在属性初始化程序中使用实例成员 'landmark';属性初始化程序在 'self' 可用之前运行”

当我将 fetch 放在身体后面时,我得到:

“包含声明的闭包不能与函数构建器'ViewBuilder'一起使用”(参考var评级)

有没有一种简单的方法可以解决这个难题,还是我必须回到众所周知的绘​​图板上?谢谢。

4

2 回答 2

0

感谢那些提供建议的人。经过长时间的中断,我回到了这个问题并得出了这个解决方案(基于HackingWithSwift教程:https ://www.hackingwithswift.com/books/ios-swiftui/dynamically-filtering-fetchrequest-with-swiftui )这里是代码:

struct RatingsView: View {
    var fetchRequest: FetchRequest<Rating>
    
    var body: some View {

        HStack(spacing: 0.4){
            ForEach(1...5) { number in
                if number > stars {
                    //Image(systemName: "star")
                } else {
                    Image(systemName: "star.fill")
                }
            }
        }
    }
    
    init(filter: String) {
        fetchRequest = FetchRequest<Rating>(entity: Rating.entity() , sortDescriptors: [], predicate: NSPredicate(format: "%K == %@", "landmark" , filter))
    }
    var sum: Int16 {
        fetchRequest.wrappedValue.reduce(0) { $0 + $1.rating }
        }
    
    var stars : Int {
        var starCount:Int
        if fetchRequest.wrappedValue.count > 0 {
            starCount = Int(sum) / fetchRequest.wrappedValue.count
        } else {
            starCount = 0
        }
        return starCount
    }
}

我不确定这是否是绝对最好的解决方案,但它按预期工作。希望这可以帮助其他人。

于 2021-05-16T00:45:40.983 回答
0

将 fetch 包装在返回 sum & stars 元组的计算属性中怎么样?形状略有不同,结果相同。计算出来的属性可以引用其他属性,这样 swift-init 的障碍就扫清了!

var metrics : (sum: Int, stars: Int) {
let fetchRequest = Rating.fetchRequestForLandmark(landmark: landmark.name)
var ratings: FetchedResults<Rating> {
    fetchRequest.wrappedValue
}

let sum = ratings.map { $0.rating }.reduce(0, +)
let stars = sum / ratings.count

return (sum: sum, stars: stars)

}

于 2021-02-13T21:44:42.387 回答