Kishor Pahalwani
Kishor Pahalwani

Reputation: 1022

error: EXC_BAD_ACCESS (code=1, address=0x6f697483). The process has been returned to the state before expression evaluation

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

Answers (1)

Jon Rose
Jon Rose

Reputation: 8563

There is a lot wrong with your code.

  1. delegates must be set as weak.
  2. 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
  3. Every ! is you asking the code to crash and should be removed
  4. methods should return what you are asking for, or should be called with a completion block to return what you are asking for. Your code is returning values using a delegate. Which is wrong.
  5. ManagedObjects (like QuizDetails) 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.
  6. ManagedObjects that are removed from the store do not automatically get set to nil. If you are holding a pointer to them after they are deleted you will crash. It is better to use a NSFetchedResultsController - even for just one object.
  7. The perform afterDelay has no value. I suspect it was added to prevent a race condition, or to otherwise paper over bugs.
  8. in 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

Related Questions