获得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
答案 0 :(得分:1)
您的代码存在很多问题。
fetchQuiz
似乎使用主要托管对象上下文进行读取。您只能从主线程运行此方法。添加DispatchQueue.main.async {
以确保此!
是您要求代码崩溃并应删除QuizDetails
)不是线程安全的 - 既不用于读取也不用于写入。必须从与其上下文关联的线程访问它们。看起来你只有一个上下文,所以我假设一个主线程上下文。 perform afterDelay
没有任何价值。我怀疑它是为了防止竞争条件而添加的,或者是用来防止错误的。fetchQuiz
中,当您已经拥有存储在变量QuizDetails
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