DispatchGroup с базой данных SQLite - PullRequest
       95

DispatchGroup с базой данных SQLite

0 голосов
/ 30 апреля 2020

Я пытаюсь разобраться в GCD, в частности в DispatchGroup, для организации загрузок в базу данных SQLite через оболочку FMDB. Мое приложение выполняет следующие действия:

  • Загружает информацию о доступных темах при запуске приложения с удаленного сервера с SQL дБ. Сохраняет их локально в базе данных SQLite для будущих сеансов и представляет то, что доступно через UITableViewController
  • . Если тема выбрана, ее содержимое загружается с сервера и сохраняется локально для будущих сеансов. Я делаю это таким образом, а не сразу при запуске, так как это предшествует покупкам в приложении. Я также загружаю некоторые другие вещи здесь. Затем перейдите к новому просмотру таблиц содержимого предмета.
  • Я могу достичь вышеизложенного путем объединения функций загрузки и сохранения вместе с обработчиками завершения, однако я хотел бы использовать DispatchGroup, чтобы я мог использовать функцию wait(timeout:) в будущем.

Однако с моей реализацией DispatchGroup (ниже) я получаю следующие ошибки.

API call with NULL database connection pointer
[logging] misuse at line 125820 of [378230ae7f]

А также

BUG IN CLIENT OF libsqlite3.dylib: illegal multi-threaded access to database connection

Код следующий:

didSelectRow

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

//Download from server
if availableSubjects[indexPath.row].isDownloaded == 0 {
    //CHAINING THIS WAY WORKS
    /* downloadModel.downloadCaseBundle(withSubjectID: indexPath.row, completion: {
       self.downloadModel.downloadToken(forSubject: indexPath.row, completion: {
       self.caseBundle = DBManager.sharedDBManager.getCaseBundle(forSubject: indexPath.row)
       self.availableSubjects[indexPath.row].isDownloaded = 1
       DispatchQueue.main.async {
           self.performSegue(withIdentifier: "showCaseList", sender: self)
           }
       })
  })*/

    let dispatchGroup = DispatchGroup()

    //Download content
    dispatchGroup.enter()
    downloadModel.downloadCaseBundle(withSubjectID: indexPath.row) {
        dispatchGroup.leave()
    }

    //Download token
    dispatchGroup.enter()
    downloadModel.downloadToken(forSubject: indexPath.row) {
        dispatchGroup.leave()
    }

    //Execute
    dispatchGroup.notify(queue: .main) {
    self.caseBundle = DBManager.sharedDBManager.getCaseBundle(forSubject: indexPath.row)
    self.availableSubjects[indexPath.row].isDownloaded = 1
    self.performSegue(withIdentifier: "showCaseList", sender: self)
    }

} else { //Already downloaded, just retrieve from local db and present
    caseBundle = DBManager.sharedDBManager.getCaseBundle(forSubject: indexPath.row)
    self.performSegue(withIdentifier: "showCaseList", sender: self)
    }       
}

DownloadModel, downloadCaseBundle

downloadToken функция более или менее идентична

func downloadCaseBundle(withSubjectID subjectID: Int, completion: @escaping () -> Void) {
    let urlPath = "someStringtoRemoteDB"
    let url: URL = URL(string: urlPath)!
    let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)

    let task = defaultSession.dataTask(with: url) { (data, response, error) in

        if error != nil {
            print("Error")
        } else {
            print("cases downloaded")
            self.parseCasesJSON(data!, header: self.remoteMasterTable, forSubject: subjectID)
            completion()
        }
    }
    task.resume()
}

Режим загрузки, анализ JSON

func parseCasesJSON(_ data:Data, header: String, forSubject subjectID: Int) {
        var jsonResult = NSArray()
        var jsonElement = NSDictionary()
        let cases = NSMutableArray()

        do {
            jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
        } catch let error as NSError {
            print(error)
            print("error at serialisation")
        }

        //Iterate through JSON result (i.e. case), construct and append to cases array
        for i in 0 ..< jsonResult.count {
            jsonElement = jsonResult[i] as! NSDictionary
            var caseObject = CaseModel()

            //The following insures none of the JsonElement values are nil through optional binding
            if let uniqueID = jsonElement["id"] as? Int,
                let subjectTitle = jsonElement["subjectTitle"] as? String,
                let subjectID = jsonElement["subjectID"] as? Int,
                let questionID = jsonElement["questionID"] as? Int,
                //And so on
            {
                caseObject.uniqueID = uniqueID
                caseObject.subjectTitle = subjectTitle
                caseObject.subjectID = subjectID
                caseObject.questionID = questionID
                //And so on
            }
            cases.add(caseObject)
        }

        DBManager.sharedDBManager.saveCasesLocally(dataToSave: cases as! [CaseModel])
        DBManager.sharedDBManager.setSubjectAsDownloaded(forSubjectID: subjectID)
    }

1 Ответ

0 голосов
/ 01 мая 2020

Оказывается, это не имело никакого отношения к этим методам, и мне нужно было реализовать FMDatabaseQueue вместо FMDatabase в моем DBManager синглтоне.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...