【问题标题】:From parse server to local sqlite (Swift 3)从解析服务器到本地 sqlite (Swift 3)
【发布时间】:2017-05-09 18:25:12
【问题描述】:

在我的应用程序中,我有一个本地 SQLite 数据库并使用解析服务器 (Back4App.com)。两者的原因是允许用户设备之间同步,如果用户删除并稍后重新安装应用程序,则可以下载数据。

我正在使用解析符号功能。他们登录后,我检查本地数据库是否有数据,如果没有,我去 Parse 并从那里下载然后将数据插入到本地数据库中。

奇怪的是,事件的顺序并没有像我预期的那样发生,这就是我的问题所在。

SigninVC 如下:

@IBAction func signinButton(sender: UIButton) {

    activityIndicator.startAnimating()

    // hides keyboard
    self.view.endEditing(true)


    // if username or password is empty
    if usernameTextField.text!.isEmpty || passwordTextField.text!.isEmpty {


        SCLAlertView().showError("Opps".localized, subTitle: "missingDetail1".localized)

    }

    // login functions
    PFUser.logInWithUsername(inBackground: self.usernameTextField.text!, password: self.passwordTextField.text!) {
        (user: PFUser?, error: Error?) -> Void in
        if let error = error {
            if let errorString = (error as NSError).userInfo["error"] as? String {
                self.activityIndicator.stopAnimating()
                NSLog(errorString);
                SCLAlertView().showError("Error".localized, subTitle: "loginError".localized)
            }
        } else {

            self.userDefault.set(PFUser.current()!.username, forKey: "username")
            self.userDefault.synchronize()
            self.activityIndicator.stopAnimating()
            self.signInCompleted ()
        }


        self.rlDatabase.checkForEmtpySpeciesDetail ()

        let datbaseCheckResult = self.userDefault.bool (forKey: "databaseEmpty")

        if datbaseCheckResult == true {

            print("No data in RLDatabase, now checking if Parse has Data")

            print("1 Calling downloadFromParse function")


            self.downloadFromParse { [weak self] in

                print("6 Calling insertParseToSQLite function")

                self?.rlDatabase.insertParseToSQLite()
            }


        } else {

//                print("Database Not empty, no update needed")

        }

    }
}

func downloadFromParse (_ completion: ()->()) {

    print("2 Starting downloadFromParse function")

    userDefault.bool (forKey: "parseHasData")

    var userCommonNameArray = parseArrayModel.userCommonNameArray
    var userCommonNameESArray = parseArrayModel.userCommonNameESArray
    var userCommonNameFRArray = parseArrayModel.userCommonNameFRArray
    var userCommonNameDEArray = parseArrayModel.userCommonNameDEArray
    var speciesNameArray = parseArrayModel.speciesNameArray
    var userNotesArray = parseArrayModel.userNotesArray


    let downloadQuery = PFQuery(className:"ReefLifeApps")
    downloadQuery.whereKey("username", equalTo: PFUser.current()!.username!)

    downloadQuery.findObjectsInBackground {(downloadedData, error) -> Void in
        if error == nil {

            print("3 begining downloadQuery")

            for downloadData in downloadedData! {

                userCommonNameArray.append(downloadData.object(forKey: "userCommonName") as! String)
                userCommonNameESArray.append(downloadData.object(forKey: "userCommonNameES") as! String)
                userCommonNameFRArray.append(downloadData.object(forKey: "userCommonNameFR") as! String)
                userCommonNameDEArray.append(downloadData.object(forKey: "userCommonNameDE") as! String)
                speciesNameArray.append(downloadData.object(forKey: "speciesName") as! String)
                userNotesArray.append(downloadData.object(forKey: "userNotes") as! String)

                print (speciesNameArray)

                print("4 finished downloadQuery")

            }

        } else {

            self.userDefault.set(false, forKey: "parseHasData")

//                print("No username registered in parse")

        }
    }

    if speciesNameArray.isEmpty == true {
        self.userDefault.set(false, forKey: "parseHasData")
    } else {
        self.userDefault.set(true, forKey: "parseHasData")
    }
    completion()

    print("5 finished downloadFromParse function")

}

RLDatabase.swift 有对 SQLite 的插入

func insertParseToSQLite () {

    print("7 begining insertParseToSQLite function")

    let parseCheckResult = self.userDefault.bool (forKey: "parseHasData")

    if parseCheckResult == true {

        let userCommonNameArray = parseArrayModel.userCommonNameArray
        let userCommonNameESArray = parseArrayModel.userCommonNameESArray
        let userCommonNameFRArray = parseArrayModel.userCommonNameFRArray
        let userCommonNameDEArray = parseArrayModel.userCommonNameDEArray
        let speciesNameArray = parseArrayModel.speciesNameArray
        let userNotesArray = parseArrayModel.userNotesArray


            var statement: OpaquePointer? = nil

            let update = String(format:"UPDATE RL_Species SET user_common_name = '\(userCommonNameArray)', user_common_name_fr = '\(userCommonNameFRArray)', user_common_name_es = '\(userCommonNameESArray)', user_common_name_de = '\(userCommonNameDEArray)', user_notes = '\(userNotesArray)' WHERE RL_Species.specie = '\(speciesNameArray)';")

        print("8 starting SQLite3 insert")

            if sqlite3_prepare_v2(database, update, -1, &statement, nil) == SQLITE_OK {

                if sqlite3_step(statement) == SQLITE_DONE {
//                        print("Successfully updated database with Parse data.")
                } else {
//                        print("Could NOT Update database with Parse data.")
                }

            } else {

                // forces SQLite to send error messagesddd
                let errorMessage = String.init(validatingUTF8: sqlite3_errmsg(database))!
                print("update failed! \(errorMessage)")
        }

            sqlite3_finalize(statement)

    } else {

    }

    print("9 finishing insertParseToSQLite function")

}

ParseArrayModel.swift

struct ParseArrayModel
{
    var userCommonNameArray = [String]()
    var userCommonNameESArray = [String]()
    var userCommonNameFRArray = [String]()
    var userCommonNameDEArray = [String]()
    var speciesNameArray = [String]()
    var userNotesArray = [String]()

}

如您所见,第一个调用是从 Parse 下载,然后调用插入函数。但是,发生的事情是它转到了 downloadFromParse,但是在

downloadQuery.findObjectsInBackground {(downloadedData, error) -> Void in

它跳过函数的其余部分,然后转到 insertToSQLite 函数,由于数组中没有数据,因此没有插入任何内容。然后它返回到 DownloadFromParse,然后抓取数据。所以,最后,所有数据都在那里,但事件顺序错误。

完全被难住了。非常感谢任何帮助。

编辑: 添加 // 打印行以显示更新后的顺序。

这是控制台显示的内容:

No data in RLDatabase, now checking if Parse has Data
1 Calling downloadFromParse function
2 Starting downloadFromParse function
6 Calling insertParseToSQLite function
7 begining insertParseToSQLite function
9 finishing insertParseToSQLite function
5 finished downloadFromParse function
3 begining downloadQuery
["Acanthaster planci"]
4 finished downloadQuery

【问题讨论】:

    标签: swift sqlite swift3 parse-server back4app


    【解决方案1】:

    这是因为您在后台异步下载,因此您的代码将在该过程进行时继续执行。您需要创建一个回调来让您知道下载何时完成,然后您可以调用下一个函数。

    func downloadFromParse (_ completion: ()->()) {
    
    userDefault.bool (forKey: "parseHasData")
    
    var userCommonNameArray = parseArrayModel.userCommonNameArray
    var userCommonNameESArray = parseArrayModel.userCommonNameESArray
    var userCommonNameFRArray = parseArrayModel.userCommonNameFRArray
    var userCommonNameDEArray = parseArrayModel.userCommonNameDEArray
    var speciesNameArray = parseArrayModel.speciesNameArray
    var userNotesArray = parseArrayModel.userNotesArray
    
    
    let downloadQuery = PFQuery(className:"ReefLifeApps")
    downloadQuery.whereKey("username", equalTo: PFUser.current()!.username!)
    
    downloadQuery.findObjectsInBackground {(downloadedData, error) -> Void in
        if error == nil {
    
            for downloadData in downloadedData! {
    
                userCommonNameArray.append(downloadData.object(forKey: "userCommonName") as! String)
                userCommonNameESArray.append(downloadData.object(forKey: "userCommonNameES") as! String)
                userCommonNameFRArray.append(downloadData.object(forKey: "userCommonNameFR") as! String)
                userCommonNameDEArray.append(downloadData.object(forKey: "userCommonNameDE") as! String)
                speciesNameArray.append(downloadData.object(forKey: "speciesName") as! String)
                userNotesArray.append(downloadData.object(forKey: "userNotes") as! String)
    
                print (speciesNameArray)
    
    
            }
    
        } else {
    
            self.userDefault.set(false, forKey: "parseHasData")
    
            print("No username registered in parse")
    
        }
    }
    
    if speciesNameArray.isEmpty == true {
        self.userDefault.set(false, forKey: "parseHasData")
    } else {
        self.userDefault.set(true, forKey: "parseHasData")
    }
     completion()
    }
    

    那么你可以这样做:

     downloadFromParse { [weak self] in
         // call next function knowing the parse download is complete.
     }
    

    【讨论】:

    • 嗨贾斯汀,谢谢,但没有完全解决。请参阅上面帖子中的编辑。
    【解决方案2】:

    我发布结果是为了帮助任何可能遇到希望将数据从解析服务器传输到本地数据库(在我的例子中是 SQLite)的问题的人。

    我无需在调用 insertToSQLite 函数之前尝试完成下载,只需在查询调用中添加 insertToSQLite 函数即可。

    加上我身边的一些其他程序员错误。以下是测试后的结果:

    var userCommonNameArray = String()
    var userCommonNameESArray = String()
    var userCommonNameFRArray = String()
    var userCommonNameDEArray = String()
    var speciesNameArray = String()
    var userNotesArray = String()
    var speciesIDArray = Int()
    
    func txFromParseToSQLite () {
    
        let downloadQuery = PFQuery(className:"ReefLifeApps")
    
        downloadQuery.whereKey("username", equalTo: PFUser.current()!.username!)
    
        downloadQuery.findObjectsInBackground {(downloadedData, error) -> Void in
            if error == nil {
    
                if (downloadedData?.count == 0) {
    
                    print("DownloadData.count == 0")
    
                    return
    
                } else {
    
                    if let downloadedData = downloadedData {
                        for downloadData in downloadedData {
    
                            self.userCommonNameArray = downloadData["userCommonName"] as! String
                            self.userCommonNameFRArray = downloadData["userCommonNameFR"] as! String
                            self.userCommonNameESArray = downloadData["userCommonNameES"] as! String
                            self.userCommonNameDEArray = downloadData["userCommonNameDE"] as! String
                            self.userNotesArray = downloadData["userNotes"] as! String
                            self.speciesNameArray = downloadData["speciesName"] as! String
                            self.speciesIDArray = downloadData["speciesID"] as! Int
    
                            print (downloadData)
    
                            self.insertParseToSQLite ()
                        }
                    }
                }
            }
        }
    }
    
    func insertParseToSQLite () {
    
            var statement: OpaquePointer? = nil
    
            let update = String(format:"UPDATE RL_User SET user_common_name = '\(userCommonNameArray)', user_common_name_fr = '\(userCommonNameFRArray)', user_common_name_es = '\(userCommonNameESArray)', user_common_name_de = '\(userCommonNameDEArray)', user_notes = '\(userNotesArray)', speciesName = '\(speciesNameArray)' WHERE id = \(speciesIDArray);")
    
            if sqlite3_prepare_v2(databaseUser, update, -1, &statement, nil) == SQLITE_OK {
    
                if sqlite3_step(statement) == SQLITE_DONE {
                } else {
                }
    
            } else {
                let errorMessage = String.init(validatingUTF8: sqlite3_errmsg(databaseUser))!
                print("update failed! \(errorMessage)")
            }
        sqlite3_finalize(statement)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-22
      • 1970-01-01
      • 1970-01-01
      • 2017-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-18
      相关资源
      最近更新 更多