提问人:Ft klee 提问时间:11/8/2023 最后编辑:Ft klee 更新时间:11/13/2023 访问量:25
如果计算属性不起作用,如何传递 attritube 以在 Swift 中制作动态谓词?[复制]
How to pass an attritube to make a dynamic predicate in Swift if computed property doesn't work? [duplicate]
问:
我正在使用抽认卡应用程序,发现我的逻辑有问题。首先,我想将表示名称的 @Binding变量(表示用户可以通过点击按钮分配给卡片的类别)传递给 ,但是,我收到一个错误: 。
下面是用户研究的视图的代码:[Int]
selectedCategories
@FetchRequest
Cannot use instance member 'selectedCategories' within property initializer; property initializers run before 'self' is available
struct FlashcardSetView: View {
var selectedCategoryIds: [Int] {
var categories: [Int] = []
for category in selectedCategories {
if category.isSelected {
categories.append(category.category)
}
}
return categories
}
// Computed property to generate the predicate for selectedCategoryCards
@FetchRequest(
entity: FlashCardData.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \FlashCardData.date, ascending: false)]
)
var selectedCategoryCards: FetchedResults<FlashCardData>
@Binding var studyPhase: StudyPhase
var set: FlashSets
init(cardSet: FlashSets, selectedCategories: Binding<[CategorySelection]>, studyPhase: Binding<StudyPhase>) {
self.set = cardSet
self._studyPhase = studyPhase
self._selectedCategories = selectedCategories
var selectedCategoryIds = selectedCategories.wrappedValue
.filter { $0.isSelected }
.map { $0.category }
let selectedCategoryPredicate = NSPredicate(format: "cardStatus IN %@", selectedCategoryIds)
_selectedCategoryCards = FetchRequest(
entity: FlashCardData.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \FlashCardData.date, ascending: false)],
predicate: selectedCategoryPredicate
)
}
@Binding var selectedCategories: [CategorySelection]
// for this predicate, I receive error statement for attribute "selectedCategories"
var set: FlashSets
@ObservedObject var dataController = DataController.shared
@Environment(\.managedObjectContext) var managedObjectContext
@State private var showTermDefinitionView = false
@Environment(\.dismiss) var dismiss
@Binding var studyPhase: StudyPhase
@State private var currentlySelectedCard: FlashCardData?
@State var isLearned = false //1
@State var isThink = false //2
@State var isHard = false // 3
@State var isRepeat = false // 4
//@State private var studyPhase: StudyPhase = .initial
@State var currentCardIndex = 0
@State private var toEndView = false
var body: some View {
NavigationView {
ZStack {
NavigationLink(destination: EndView(set: set), isActive: $toEndView) {
EmptyView()
}
Text("Card list is empty😕")
.offset(y: -50)
if studyPhase == .initial {
ForEach(set.cardsArray, id: \.self) { card in
VStack {
Text("Number of Cards: \(set.cardsArray.count)") // !displays the number of cards
.font(.headline)
SingleFlashCard(cards: set.cardsArray,
removal: {
withAnimation(.easeInOut) {
removeCurrentCard()
}
print("Removing card with animation")
}, currentCardIndex: $currentCardIndex, isLearned: $isLearned,
isThink: $isThink,
isHard: $isHard,
isRepeat: $isRepeat)
.transition(.asymmetric(insertion: .opacity, removal: .opacity))
}
.onAppear {
currentlySelectedCard = card
// Automatically transition to the EndView when all cards are studied
}
}
}
if studyPhase == .hard {
ForEach(selectedCategoryCards, id: \.self) { card in
// if let unwrappedCard = card {
// //Text(unwrappedCard.name)
// }
VStack {
Text(selectedCategoryCards.count.description)
SingleFlashCard(cards: set.cardsArray,
removal: {
withAnimation(.easeInOut) {
removeCurrentCard()
}
print("Removing card with animation")
}, set: set, currentCardIndex: $currentCardIndex, isLearned: $isLearned,
isThink: $isThink,
isHard: $isHard,
isRepeat: $isRepeat, studyPhase: $studyPhase, selectedCategoryIds: selectedCategoryIds)
.transition(.asymmetric(insertion: .opacity, removal: .opacity))
}
.onAppear {
currentlySelectedCard = card
print("Appeared with \(selectedCategoryCards.count) cards")
}
}
}
private func removeCurrentCard() {
if studyPhase == .initial {
if currentCardIndex < set.cardsArray.count - 1 {
currentCardIndex += 1 // Move to the next card
currentlySelectedCard = set.cardsArray[currentCardIndex] // Update currentlySelectedCard
} else {
if set.cardsArray.last != nil {
// All cards in the set have been studied
toEndView = true // Transition to the EndView
}
// else {
// studyPhase = .hard // Transition to the "hard" study phase if there are more cards
// }
}
} else if studyPhase == .hard {
if currentCardIndex < selectedCategoryCards.count - 1 {
currentCardIndex += 1 // Move to the next card
currentlySelectedCard = selectedCategoryCards[currentCardIndex] // Update currentlySelectedCard
} else {
if selectedCategoryCards.last != nil {
// All "hard" cards are studied
toEndView = true // Transition to the EndView
} else {
// Handle the case when there are more cards in category 3
}
}
}
}
}
}
}}
以下是用户选择类别的视图:
import SwiftUI
struct EndView: View {
var set: FlashSets
@ObservedObject var dataController = DataController.shared
@State private var continueFlashying = false
@State private var returnHome = false
@Binding var selectedCategories: [CategorySelection]
var selectedCardStatuses: [Int] {
return selectedCategories.filter { $0.isSelected }.map { $0.category }
}
@Binding var studyPhase: StudyPhase
@State private var showAlert = false
@State private var restartSet = false
@Environment(\.presentationMode) var presentationMode
@Environment(\.dismiss) var dismiss
var body: some View {
NavigationStack {
VStack {
Text("Set finished👍")
.bold()
.font(.system(size: 36))
.padding()
// Display the number of cards in each category
List {
ForEach(1...4, id: \.self) { category in
CategoryRow(categoryName: "Category \(category) cards studied: \(set.cardsArray.filter { $0.cardStatus == category }.count)", category: category, isSelected: $selectedCategories[category - 1].isSelected)
}
}
NavigationStack {
Button(action: {
if hasSelectedCategories() {
continueFlashying = true
//FlashCardSetView.studyPhase = .initial
} else {
showAlert = true
}
studyPhase = .hard
//dismiss()
}) {
Text("Continue studying")
.underline()
NavigationLink(destination: FlashcardSetView(selectedCategories: $selectedCategories, studyPhase: $studyPhase, set: set), isActive: $continueFlashying) {
EmptyView()
}
}
Button(action: {
// Handle the "Start again" button
restartSet = true
studyPhase = .initial
}) {
Text("Start again")
.underline()
}
NavigationLink(destination: FlashcardSetView(selectedCategories: $selectedCategories, studyPhase: $studyPhase, set: set), isActive: $restartSet) {
EmptyView()
}
Button(action: {
returnHome = true
}) {
// Return home button
Text("Return Home")
.underline()
}
.fullScreenCover(isPresented: $returnHome) {
NewHomeView()
}
}
}
}
.navigationBarBackButtonHidden(true)
.alert(isPresented: $showAlert) {
Alert(
title: Text("No cards selected"),
message: Text("Please select at least one category with cards to continue studying."),
dismissButton: .default(Text("OK"))
)
}
}
private func hasSelectedCategories() -> Bool {
return selectedCategories.contains { $0.isSelected } || selectedCategories.isEmpty
}}
struct CategoryRow: View {
let categoryName: String
var category: Int
@Binding var isSelected: Bool
var body: some View {
HStack {
Text(categoryName)
Spacer()
CheckboxView(isSelected: $isSelected)
}
}}
struct CheckboxView: View {
@Binding var isSelected: Bool
var body: some View {
Button(action: {
isSelected.toggle()
}) {
Image(systemName: isSelected ? "checkmark.circle.fill" : "circle")
.foregroundColor(isSelected ? .green : .secondary)
}
}
}
答: 暂无答案
评论