如果计算属性不起作用,如何传递 attritube 以在 Swift 中制作动态谓词?[复制]

How to pass an attritube to make a dynamic predicate in Swift if computed property doesn't work? [duplicate]

提问人:Ft klee 提问时间:11/8/2023 最后编辑:Ft klee 更新时间:11/13/2023 访问量:25

问:

我正在使用抽认卡应用程序,发现我的逻辑有问题。首先,我想将表示名称的 @Binding变量(表示用户可以通过点击按钮分配给卡片的类别)传递给 ,但是,我收到一个错误: 。 下面是用户研究的视图的代码:[Int]selectedCategories@FetchRequestCannot 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)
    }
}

}

结构类别选择 { var 类别: Int var isSelected = 假 }Flashy Entity

FlashCardData Entity

iOS Swift SwiftUI 核心数据

评论


答: 暂无答案