错误:EXC_BAD_ACCESS(代码= 1,地址= 0x6f697483)。该过程已返回到表达式评估之前的状态

时间:2018-05-08 10:33:25

标签: swift exception core-data alamofire

获得API成功响应后,我正在保存,更新并从核心数据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是我的协议。 QuizDetails是我的模型结构。

我创建了一个结构(模型),在从核心数据中获取数据时,我正在创建模型并通过委托传递给我的控制器类。

我不知道它有时工作正常,但有时会发生突然崩溃。

  

线程1:EXC_BAD_ACCESS(代码= 1,地址= 0x50000010)

我尝试了不同的方法,但意外地崩溃了。

是否有与数据库相关的内容我必须更改? 还是其他任何概念?

'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

1 个答案:

答案 0 :(得分:1)

您的代码存在很多问题。

  1. 代表必须设置为弱。
  2. fetchQuiz似乎使用主要托管对象上下文进行读取。您只能从主线程运行此方法。添加DispatchQueue.main.async {以确保此
  3. 每个!是您要求代码崩溃并应删除
  4. 方法应该返回您要求的内容,或者应该使用完成块调用以返回您要求的内容。您的代码使用委托返回值。这是错的。
  5. ManagedObjects(如QuizDetails)不是线程安全的 - 既不用于读取也不用于写入。必须从与其上下文关联的线程访问它们。看起来你只有一个上下文,所以我假设一个主线程上下文。
  6. 从商店中删除的ManagedObjects不会自动设置为nil。如果你在删除指针后拿着指针,你就会崩溃。最好使用NSFetchedResultsController - 即使只有一个对象。
  7. perform afterDelay没有任何价值。我怀疑它是为了防止竞争条件而添加的,或者是用来防止错误的。
  8. fetchQuiz中,当您已经拥有存储在变量QuizDetails
  9. 中的刚刚获取的value时,似乎没有理由创建 self.saveUpdateQuizInfoDB(json: json) self.perform(#selector(self.fetchQuiz(quizID:)), with: quizID, afterDelay: 0.2)

    所有这些都是应该修复的实际问题。崩溃的最直接原因是#2 - (从错误的线程访问核心数据)。替换

        DispatchQueue.main.async {
            self.saveUpdateQuizInfoDB(json: json)
            self.fetchQuiz(quizID:quizID)
        }
    

    initialize