SwiftUI和Core Data:在视图内部使用实例成员作为参数的fetch请求



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

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

下面是获取(当获取的参数是硬编码时,它会像预期的那样工作):

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放到body之后,我得到:

"包含声明的闭包不能与函数构建器'ViewBuilder'"(参考var评级)

是否有简单的方法来解决这个难题,或者我必须回到众所周知的绘图板?谢谢。

如何将fetch包装在一个计算属性中,返回一个sum &星元组吗?形状稍有不同,结果却一样。计算出的属性可以引用其他属性,这样就清除了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)

}

感谢那些提出建议的人。经过长时间的中断,我回到这个问题,并得出了这个解决方案(基于一个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
}
}

我不确定这是否是绝对最好的解决方案,但它是按预期工作。

最新更新