i am new on swift language , i hava an app with code to parse and decode json then reserve it to core information and a few core information func the fetch particular information , i dont know the best way to change it to swiftdata
anybody have thought ?
particularly the parseAndStoreQuizJSONData func and the delete func
the best way to take care of that please ?
class QuizDataViewModel: ObservableObject {
// MARK: Quiz for Board funcs
@Printed var selectedBoardQuizQuestions : [QuizQuestion] = []
@Printed var selectedQuizSystem: QuizSystem?
func numberOfQuestionsForBoardFor(month: Int, half: Int, 12 months: Int) -> Int {
guard let quizQuestions = selectedQuizSystem?.quizQuestions?.allObjects as? [QuizQuestion] else { return 0 }
return quizQuestions.filter {
let (questionPart, questionMonth, questionYear, _) = extractDataFromId(id: Int($0.id))
return questionYear == 12 months && questionPart == half && questionMonth == month
}.rely
}
func selectQuestionsForBoardQuiz(_ numberOfQuestions: Int, for month: Int, half: Int, 12 months: Int) {
guard let quizQuestions = selectedQuizSystem?.quizQuestions?.allObjects as? [QuizQuestion] else { return }
let relevantQuestions = quizQuestions.filter {
let (questionPart, questionMonth, questionYear, _) = extractDataFromId(id: Int($0.id))
return questionYear == 12 months && questionPart == half && questionMonth == month
}
if numberOfQuestions >= relevantQuestions.rely {
// If we're asking for all questions (or extra), kind them by id
selectedBoardQuizQuestions = relevantQuestions.sorted(by: { $0.id < $1.id })
} else {
// If we're asking for a subset of questions, choose randomly
selectedBoardQuizQuestions = Array(relevantQuestions.shuffled().prefix(numberOfQuestions))
}
}
func extractDataFromId(id: Int) -> (half: Int, month: Int, 12 months: Int, questionId: Int) {
let idString = String(id)
let half = Int(idString.prefix(1))
let month = Int(idString.dropFirst(1).prefix(2))
let 12 months = Int(idString.dropFirst(3).prefix(4))
let questionId = Int(idString.dropFirst(7))
return (half ?? 0, month ?? 0, 12 months ?? 0, questionId ?? 0)
}
func uniqueYearsFromQuestions(in system: QuizSystem) -> [Int] {
guard let quizQuestions = system.quizQuestions?.allObjects as? [QuizQuestion] else { return [] }
let years = Set(quizQuestions.map { extractDataFromId(id: Int($0.id)).12 months })
return Array(years).sorted(by: >) // kind in descending order
}
func uniquePartsForYear(12 months: Int, in system: QuizSystem) -> [Int] {
guard let quizQuestions = system.quizQuestions?.allObjects as? [QuizQuestion] else { return [] }
let components = Set(quizQuestions.filter {
let extractedYear = extractDataFromId(id: Int($0.id)).12 months
return extractedYear == 12 months
}.map {
let extractedPart = extractDataFromId(id: Int($0.id)).half
return extractedPart
})
let uniqueParts = Array(components).sorted() // kind in ascending order
return uniqueParts
}
func uniqueMonthsForPart(half: Int, 12 months: Int, in system: QuizSystem) -> [Int] {
guard let quizQuestions = system.quizQuestions?.allObjects as? [QuizQuestion] else { return [] }
let months = Set(quizQuestions.filter {
let (questionPart, _, questionYear, _) = extractDataFromId(id: Int($0.id))
return questionYear == 12 months && questionPart == half
}.map {
let extractedMonth = extractDataFromId(id: Int($0.id)).month
return extractedMonth
})
let uniqueMonths = Array(months).sorted() // kind in ascending order
return uniqueMonths
}
func fetchQuizSystemForId(systemID: Int64, branchID: Int64) {
let context = container.viewContext
let fetchRequest: NSFetchRequest<QuizSystem> = QuizSystem.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "id == %d AND quizBranch.id == %d", systemID, branchID)
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
do {
let fetchedSystems = attempt context.fetch(fetchRequest)
self.selectedQuizSystem = fetchedSystems.first // replace selectedQuizSystem
} catch {
print("Didn't fetch QuizSystem: (error)")
}
}
// ---------------------------------------------
// MARK: Func for saving any information to coredata
func saveChanges() {
let context = container.viewContext
if context.hasChanges {
do {
attempt context.save()
// Toggle the refreshFlag to power a UI replace
self.refreshFlag.toggle()
} catch {
let nserror = error as NSError
fatalError("Unresolved error (nserror), (nserror.userInfo)")
}
}
}
// ---------------------------------------------
// MARK: Func for QuizRandoms
@Printed var quizSystems = [QuizSystem]()
@Printed var quizQuestions: [QuizQuestion] = []
@Printed var selectedSystemName: String?
@Printed var currentSystemIndex = 0
@Printed var quizTimeRemaining = 900
func fetchQuizSystems(for branchID: Int64, excludingSystemIDs: [Int64] = []) {
let context = container.viewContext
context.carry out {
let fetchQuizSystemRequest: NSFetchRequest<QuizSystem> = QuizSystem.fetchRequest()
var predicates = [NSPredicate(format: "quizBranch.id == %d", branchID)]
for id in excludingSystemIDs {
let excludePredicate = NSPredicate(format: "id != %d", id)
predicates.append(excludePredicate)
}
fetchQuizSystemRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)
fetchQuizSystemRequest.sortDescriptors = [NSSortDescriptor(keyPath: QuizSystem.id, ascending: true)]
do {
let fetchedQuizSystems = attempt context.fetch(fetchQuizSystemRequest)
self.quizSystems = fetchedQuizSystems
} catch {
print("Didn't fetch QuizSystem: (error)")
}
}
}
func fetchQuizQuestions(for systemID: Int64, and branchID: Int64) {
let context = container.viewContext
let fetchRequest: NSFetchRequest<QuizQuestion> = QuizQuestion.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "quizSystem.id == %d AND quizSystem.quizBranch.id == %d", systemID, branchID)
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
do {
self.quizQuestions = attempt context.fetch(fetchRequest)
} catch {
print("Didn't fetch QuizQuestion objects: (error)")
}
}
func selectRandomQuestions(_ rely: Int) {
guard quizQuestions.rely >= rely else {
print("Not sufficient questions to pick from.")
return
}
quizQuestions.shuffle()
quizQuestions = Array(quizQuestions.prefix(rely))
}
// -------------------------------------------
// MARK: Func for Downloading and updating information from server
@AppStorage("selectedBranchName") var selectedBranchName: String?
let urlSession = URLSession.shared
let container: NSPersistentContainer
init(container: NSPersistentContainer) {
self.container = container
self.parseAndStoreQuizJSONData()
}
func fetchAndDecodeQuizJSONData(from url: URL, utilizing urlSession: URLSession = URLSession.shared, completion: @escaping (End result<QuizBranchTemp, Error>) -> Void) {
let activity = urlSession.dataTask(with: url) { information, response, error in
if let error = error {
completion(.failure(error))
print("One thing went flawed: (error)")
return
}
guard let information = information else {
completion(.failure(NSError(area: "", code: -1, userInfo: nil)))
return
}
let decoder = JSONDecoder()
do {
let decodedData = attempt decoder.decode(QuizBranchTemp.self, from: information)
completion(.success(decodedData))
} catch {
completion(.failure(error))
}
}
activity.resume()
}
func parseAndStoreQuizJSONData() {
let context = container.newBackgroundContext()
context.carry out {
guard let mainURL = URL(string: "https://instance.com/identify.json") else {
print("Invalid URL")
return
}
var request = URLRequest(url: mainURL)
request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData
URLSession.shared.dataTask(with: request) { (information, response, error) in
if let error = error {
print("Didn't fetch foremost Quiz JSON: (error)")
return
}
guard let httpResponse = response as? HTTPURLResponse else {
print("Invalid response")
return
}
guard httpResponse.statusCode == 200 else {
print("HTTP Standing Code: (httpResponse.statusCode)")
return
}
guard let information = information else {
print("No information returned from foremost Quiz JSON")
return
}
let decoder = JSONDecoder()
do {
let quizMainData = attempt decoder.decode(QuizMainData.self, from: information)
let quizStoredVersion = UserDefaults.commonplace.string(forKey: "quizMainDataVersion") ?? ""
print("Fetched quizMainDataVersion: (quizMainData.quizMainDataVersion)")
print("Saved quizMainDataVersion: (quizStoredVersion)")
if quizMainData.quizMainDataVersion == quizStoredVersion {
print("quizMainDataVersion is similar because the quizStored model.")
return
}
var parsedQuizBranchIDs = Set<Int64>()
var parsedQuizSystemIDs = Set<Int64>()
var parsedQuizQuestionIDs = Set<Int64>()
let group = DispatchGroup()
for quizBranchInfo in quizMainData.quizMainDataContent {
print("Processing quizBranch: (quizBranchInfo.branchName)")
let lastVersion = UserDefaults.commonplace.string(forKey: "(quizBranchInfo.branchName)Model") ?? ""
// Add this department's ID to parsedBranchIDs
parsedQuizBranchIDs.insert(Int64(quizBranchInfo.id))
if quizBranchInfo.model == lastVersion {
print("(quizBranchInfo.branchName) model is similar as the present model. Aborting...")
proceed
}
guard let quizBranchURL = URL(string: quizBranchInfo.url) else {
print("Invalid URL for department: (quizBranchInfo.branchName)")
proceed
}
group.enter()
self.fetchAndDecodeQuizJSONData(from: quizBranchURL, utilizing: self.urlSession) { lead to
defer { group.depart() }
swap outcome {
case .success(let quizBranch):
do {
let fetchQuizBranchRequest: NSFetchRequest<QuizBranch> = QuizBranch.fetchRequest()
fetchQuizBranchRequest.predicate = NSPredicate(format: "id == %d", quizBranch.id)
let fetchedQuizBranches = attempt context.fetch(fetchQuizBranchRequest)
let QuizBranchEntity = fetchedQuizBranches.first ?? QuizBranch(context: context)
QuizBranchEntity.id = Int64(quizBranch.id)
QuizBranchEntity.branchName = quizBranch.branchName
for quizSystem in quizBranch.quizSystems {
let fetchQuizSystemRequest: NSFetchRequest<QuizSystem> = QuizSystem.fetchRequest()
fetchQuizSystemRequest.predicate = NSPredicate(format: "id == %d AND quizBranch.id == %d", quizSystem.id, quizBranch.id)
let fetchedQuizSystems = attempt context.fetch(fetchQuizSystemRequest)
let quizSystemEntity = fetchedQuizSystems.first ?? QuizSystem(context: context)
quizSystemEntity.id = Int64(quizSystem.id)
quizSystemEntity.systemName = quizSystem.systemName
quizSystemEntity.systemSubheadline = quizSystem.systemSubheadline
quizSystemEntity.systemImage = quizSystem.systemImage
quizSystemEntity.quizBranch = QuizBranchEntity
parsedQuizSystemIDs.insert(quizSystemEntity.id)
for quizQuestion in quizSystem.quizQuestions {
let fetchQuizQuestionRequest: NSFetchRequest<QuizQuestion> = QuizQuestion.fetchRequest()
fetchQuizQuestionRequest.predicate = NSPredicate(format: "id == %d AND quizSystem.id == %d AND quizSystem.quizBranch.id == %d", quizQuestion.id, quizSystem.id, quizBranch.id)
let fetchedQuizQuestions = attempt context.fetch(fetchQuizQuestionRequest)
let quizQuestionEntity = fetchedQuizQuestions.first ?? QuizQuestion(context: context)
quizQuestionEntity.id = Int64(quizQuestion.id)
quizQuestionEntity.questionNumber = Int64(quizQuestion.questionNumber)
quizQuestionEntity.questionContent = quizQuestion.questionContent
quizQuestionEntity.choiceA = quizQuestion.choiceA
quizQuestionEntity.choiceB = quizQuestion.choiceB
quizQuestionEntity.choiceC = quizQuestion.choiceC
quizQuestionEntity.choiceD = quizQuestion.choiceD
quizQuestionEntity.choiceE = quizQuestion.choiceE
quizQuestionEntity.correctAnswerLetter = quizQuestion.correctAnswerLetter
quizQuestionEntity.clarification = quizQuestion.clarification
quizQuestionEntity.isSolvedWrong = quizQuestion.isSolvedWrong
quizQuestionEntity.isFlagged = quizQuestion.isFlagged
quizQuestionEntity.isNeedReview = quizQuestion.isNeedReview
quizQuestionEntity.quizSystem = quizSystemEntity
parsedQuizQuestionIDs.insert(quizQuestionEntity.id)
}
}
do {
attempt context.save()
print("Saved new model ((String(describing: quizBranchInfo.model))) of (quizBranchInfo.branchName) to Quiz CoreData")
} catch {
print("Failed to save lots of Quiz Core Knowledge: (error)")
}
} catch {
print("Didn't fetch and parse Quiz information: (error)")
}
UserDefaults.commonplace.set(quizBranchInfo.model, forKey: "(quizBranchInfo.branchName)Model")
print("Set (quizBranchInfo.branchName) model to (quizBranchInfo.model)")
case .failure(let error):
print("Didn't decode Quiz JSON for Quiz department (quizBranchInfo.branchName): (error)")
}
}
}
group.notify(queue: .foremost) {
print("Parsed Quiz department IDs: (parsedQuizBranchIDs)")
// Now it is protected to delete
do {
self.deleteEntitiesNotInParsedIDs(context: context, entityName: "QuizBranch", parsedIDs: parsedQuizBranchIDs)
self.deleteEntitiesNotInParsedIDs(context: context, entityName: "QuizSystem", parsedIDs: parsedQuizSystemIDs)
self.deleteEntitiesNotInParsedIDs(context: context, entityName: "QuizQuestion", parsedIDs: parsedQuizQuestionIDs)
attempt context.save()
UserDefaults.commonplace.set(quizMainData.quizMainDataVersion, forKey: "quizMainDataVersion")
} catch {
print("Didn't decode foremost Quiz JSON: (error)")
}
}
} catch {
print("Didn't decode foremost Quiz JSON: (error)")
}
}.resume()
}
}
func deleteEntitiesNotInParsedIDs(context: NSManagedObjectContext, entityName: String, parsedIDs: Set<Int64>) {
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: entityName)
do {
let fetchedEntities = attempt context.fetch(fetchRequest)
for object in fetchedEntities {
if let entity = object as? NSManagedObject, let entityId = entity.worth(forKey: "id") as? Int64 {
if !parsedIDs.incorporates(entityId) {
context.delete(entity)
}
}
}
} catch {
print("Didn't fetch (entityName)s: (error)")
}
}
// ----------------------------------------------------------------
// MARK: Func for Trainging heart
@Printed var refreshFlag: Bool = false
func fetchIsFlaggedQuestionsBySystem(for branchID: Int64) -> ([String: [QuizQuestion]], [QuizSystem]) {
var isFlaggedQuizQuestionBySystem = [String: [QuizQuestion]]()
var isFlaggedQuizSystemsArray = [QuizSystem]()
// Fetch techniques for the chosen department
self.fetchQuizSystems(for: branchID)
for system in self.quizSystems {
// Fetch flagged questions for the system
let flaggedQuestions = fetchIsFlaggedQuestions(for: system.id)
// Solely add the system to the dictionary if it has flagged questions
if !flaggedQuestions.isEmpty {
isFlaggedQuizQuestionBySystem[system.systemName!] = flaggedQuestions
isFlaggedQuizSystemsArray.append(system)
}
}
return (isFlaggedQuizQuestionBySystem, isFlaggedQuizSystemsArray)
}
func fetchIsFlaggedQuestions(for systemID: Int64) -> [QuizQuestion] {
let context = container.viewContext
let fetchRequest: NSFetchRequest<QuizQuestion> = QuizQuestion.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "quizSystem.id == %d AND isFlagged == %d", systemID, 1)
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
do {
let flaggedQuestions = attempt context.fetch(fetchRequest)
return flaggedQuestions
} catch {
print("Didn't fetch flagged QuizQuestion objects: (error)")
}
return []
}
func fetchIsSolvedWrongQuestionsBySystem(for branchID: Int64) -> ([String: [QuizQuestion]], [QuizSystem]) {
var isSolvedWrongQuizQuestionBySystem = [String: [QuizQuestion]]()
var isSolvedWrongQuizSystemsArray = [QuizSystem]()
// Fetch techniques for the chosen department
self.fetchQuizSystems(for: branchID)
for system in self.quizSystems {
// Fetch flagged questions for the system
let isSolvedWrongQuestions = fetchIsSolvedWrongQuestions(for: system.id)
// Solely add the system to the dictionary if it has flagged questions
if !isSolvedWrongQuestions.isEmpty {
isSolvedWrongQuizQuestionBySystem[system.systemName!] = isSolvedWrongQuestions
isSolvedWrongQuizSystemsArray.append(system)
}
}
return (isSolvedWrongQuizQuestionBySystem, isSolvedWrongQuizSystemsArray)
}
func fetchIsSolvedWrongQuestions(for systemID: Int64) -> [QuizQuestion] {
let context = container.viewContext
let fetchRequest: NSFetchRequest<QuizQuestion> = QuizQuestion.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "quizSystem.id == %d AND isSolvedWrong == %d", systemID, 1)
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
do {
let isSolvedWrongQuestions = attempt context.fetch(fetchRequest)
return isSolvedWrongQuestions
} catch {
print("Didn't fetch isSolvedWrong QuizQuestion objects: (error)")
}
return []
}
func fetchIsNeedReviewQuestionsBySystem(for branchID: Int64) -> ([String: [QuizQuestion]], [QuizSystem]) {
var isNeedReviewQuizQuestionBySystem = [String: [QuizQuestion]]()
var isNeedReviewQuizSystemsArray = [QuizSystem]()
// Fetch techniques for the chosen department
self.fetchQuizSystems(for: branchID)
for system in self.quizSystems {
// Fetch flagged questions for the system
let isNeedReviewQuestions = fetchIsNeedReviewQuestions(for: system.id)
// Solely add the system to the dictionary if it has flagged questions
if !isNeedReviewQuestions.isEmpty {
isNeedReviewQuizQuestionBySystem[system.systemName!] = isNeedReviewQuestions
isNeedReviewQuizSystemsArray.append(system)
}
}
return (isNeedReviewQuizQuestionBySystem, isNeedReviewQuizSystemsArray)
}
func fetchIsNeedReviewQuestions(for systemID: Int64) -> [QuizQuestion] {
let context = container.viewContext
let fetchRequest: NSFetchRequest<QuizQuestion> = QuizQuestion.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "quizSystem.id == %d AND isNeedReview == %d", systemID, 1)
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
do {
let isNeedReviewQuestions = attempt context.fetch(fetchRequest)
return isNeedReviewQuestions
} catch {
print("Didn't fetch isNeedReview QuizQuestion objects: (error)")
}
return []
}
}```
i wish to save decoded json to swiftdata