Reputation: 1022
After getting API success response, I am saving, updating and fetching the data from core data DB.
import Foundation
import SwiftyJSON
protocol WKQuizInformationVMDelegate {
func success(details: QuizDetails?, isSuccess: Bool, quizID: String)
func detailsFailure(error: String, quizID: String)
}
class WKQuizInformation: NSObject {
var quizDetails: QuizDetails?
var delegate: WKQuizInformationVMDelegate?
//Retrieve Particular Quiz Information from server
func retrieveParticularQuizInfo(quizID : String, quizVersion : String, summary: String) {
WKNetworkManager.sharedInstance.getParticularQuizDetail(clientUserID: WKQuizConstant.kClientUserIdValue, quizID: quizID, quizVersion: quizVersion, summary: summary, onSuccess: { (json) in
self.saveUpdateQuizInfoDB(json: json)
self.perform(#selector(self.fetchQuiz(quizID:)), with: quizID, afterDelay: 0.2)
}) { (error) in
print(quizID)
print(error)
self.delegate?.detailsFailure(error: error, quizID: quizID)
}
}
//MARK:- Save and Update Quiz Information in Data base
fileprivate func saveUpdateQuizInfoDB(json: JSON) {
let quizInfo = FetchDataBaseService.sharedInstance.fetchQuizInformation(quizID: json[WKQuizConstant.Id].rawString() ?? "")
var quizInfoDB: DBQuizInformation!
if quizInfo.count > 0 {
quizInfoDB = quizInfo[0]
}
else {
quizInfoDB = DBQuizInformation.init(context : FetchDataBaseService.sharedInstance.mngdCntxt)
}
quizInfoDB.id = json[WKQuizConstant.Id].rawString() ?? ""
quizInfoDB.quizVersion = json[WKQuizConstant.kQuizVersion].rawString() ?? ""
quizInfoDB.newQuestions = json[WKQuizConstant.kNewQuestions].rawString() ?? ""
quizInfoDB.navigationType = json[WKQuizConstant.kNavigationType].rawString() ?? ""
quizInfoDB.testMode = json[WKQuizConstant.kTestMode].rawString() ?? ""
quizInfoDB.questionTime = json[WKQuizConstant.kQuestionTime].rawString() ?? ""
quizInfoDB.metadataAssoc = json[WKQuizConstant.kMetadataAssoc].rawString() ?? ""
quizInfoDB.randomizeQuestion = json[WKQuizConstant.kRandomizeQuestion].rawString() ?? ""
quizInfoDB.metadataTitle = json[WKQuizConstant.kMetadataTitle].rawString() ?? ""
quizInfoDB.gotWrong = json[WKQuizConstant.kGotWrong].rawString() ?? ""
quizInfoDB.quizTime = json[WKQuizConstant.kQuizTime].rawString() ?? ""
quizInfoDB.title = json[WKQuizConstant.kTitle].rawString() ?? ""
quizInfoDB.numberOfQuestions = json[WKQuizConstant.kNumberOfQuestions].rawString() ?? ""
quizInfoDB.quizType = json[WKQuizConstant.kQuizType].rawString() ?? ""
quizInfoDB.randomizeAnswer = json[WKQuizConstant.kRandomizeQuestion].rawString() ?? ""
quizInfoDB.numberOfAvailableMetadataQuestions = json[WKQuizConstant.kNumberOfAvailableMetadataQuestions].rawString() ?? ""
quizInfoDB.totalTestQuestions = json[WKQuizConstant.kTestProgress][WKQuizConstant.kTotalTestQuestions].rawString() ?? ""
quizInfoDB.totalCorrectAnswers = json[WKQuizConstant.kTestProgress][WKQuizConstant.kTotalCorrectAnswers].rawString() ?? ""
quizInfoDB.totalWrongAnswers = json[WKQuizConstant.kTestProgress][WKQuizConstant.kTotalWrongAnswers].rawString() ?? ""
quizInfoDB.totalUnAttempted = json[WKQuizConstant.kTestProgress]["totalUnattempted"].rawString() ?? ""
quizInfoDB.numberOfMetadataQuestions = Int64(json[WKQuizConstant.kNumberOfMetadataQuestions].rawValue as? Int ?? 0)
FetchDataBaseService.sharedInstance.saveContext()
}
//Fetch Quiz Information from DB and Save it to models
@objc func fetchQuiz (quizID: String) {
let fetchQuizInfo = FetchDataBaseService.sharedInstance.fetchQuizInformation(quizID: quizID)
if fetchQuizInfo.count > 0 {
let value = fetchQuizInfo[0]
quizDetails = QuizDetails(quizVersion: value.quizVersion!,
newQuestions: value.newQuestions!,
navigationType: value.navigationType!,
testMode: value.testMode!,
questionTime: value.questionTime!,
metadataAssoc: value.metadataAssoc!,
randomizeQuestion: value.randomizeQuestion!,
id: value.id!,
metadataTitle: value.metadataTitle!,
gotWrong: value.gotWrong!,
quizTime: value.quizTime!,
title: value.title!,
numberOfQuestions: value.numberOfQuestions!,
quizType: value.quizType!,
randomizeAnswer: value.randomizeAnswer!,
numberOfAvailableMetadataQuestions: value.numberOfAvailableMetadataQuestions!,
totalTestQuestions: value.totalTestQuestions!,
totalCorrectAnswers: value.totalCorrectAnswers!,
totalWrongAnswers: value.totalWrongAnswers!,
totalUnAttempted: value.totalUnAttempted!,
numberOfMetadataQuestions: Int(value.numberOfMetadataQuestions))
self.delegate?.success(details: quizDetails, isSuccess: true, quizID: quizID)
}
else {
self.delegate?.success(details: nil, isSuccess: false, quizID: quizID)
}
}
}
WKQuizInformationVMDelegate is my protocol. QuizDetails is my model structure.
I have created a structure(model), while fetching the data from core data I am creating model and passing to it my controller class via delegate.
I don't know sometimes it is working fine but sometimes sudden crash occurs.
Thread 1: EXC_BAD_ACCESS (code=1, address=0x50000010)
I tried different ways also but getting crash unexpectedly.
Is there anything related to database I have to change ? Or any other concept?
'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x9180952e)
frame #0: 0x00dc7b4c libswiftCore.dylib`swift_unknownRelease + 8
frame #1: 0x000caa00 WKQuiz`WKQuizInformation.quizDetails.setter(value=WKQuiz.QuizDetails @ 0x0064e6c8, self=0x1805d290) at WKQuizInfoVM.swift:0
* frame #2: 0x000d59a8 WKQuiz`WKQuizInformation.fetchQuiz(quizID="307", self=0x1805d290) at WKQuizInfoVM.swift:90
frame #3: 0x000d8fe0 WKQuiz`@objc WKQuizInformation.fetchQuiz(quizID:) at WKQuizInfoVM.swift:0
frame #4: 0x1d04602e Foundation`__NSFireDelayedPerform + 458
frame #5: 0x1c6d0636 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14
frame #6: 0x1c6d0338 CoreFoundation`__CFRunLoopDoTimer + 832
frame #7: 0x1c6cfd36 CoreFoundation`__CFRunLoopDoTimers + 188
frame #8: 0x1c6cddd4 CoreFoundation`__CFRunLoopRun + 780
frame #9: 0x1c6211ae CoreFoundation`CFRunLoopRunSpecific + 470
frame #10: 0x1c620fd0 CoreFoundation`CFRunLoopRunInMode + 104
frame #11: 0x1ddcbb40 GraphicsServices`GSEventRunModal + 80
frame #12: 0x219a91d2 UIKit`UIApplicationMain + 150
frame #13: 0x001d6114 WKQuiz`main at AppDelegate.swift:15
frame #14: 0x1be0e4ea libdyld.dylib`start + 2
Upvotes: 1
Views: 2641
Reputation: 8563
There is a lot wrong with your code.
fetchQuiz
appears to read using the Main Managed Object Context. You can only run this method from the main thread. Add a DispatchQueue.main.async {
to ensure this!
is you asking the code to crash and should be removedQuizDetails
) are not thread safe - neither for reading or for writing. They must be accessed from the thread associated with their context. It looks like you have only one context, so I assume that a main-thread context. perform afterDelay
has no value. I suspect it was added to prevent a race condition, or to otherwise paper over bugs.fetchQuiz
there does not appear to be a reason that you are creating a QuizDetails
when you already have the one you just fetched stored in the variable value
All of these are real issues that should be fixed. the most likely immediate cause of your crash is #2 - (accessing core data from the wrong thread). replace
self.saveUpdateQuizInfoDB(json: json)
self.perform(#selector(self.fetchQuiz(quizID:)), with: quizID, afterDelay: 0.2)
with
DispatchQueue.main.async {
self.saveUpdateQuizInfoDB(json: json)
self.fetchQuiz(quizID:quizID)
}
Upvotes: 1