2016-12-24 33 views
0

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

我正在使用解析签名函数。他们登录后,我检查本地数据库是否有数据,如果没有,我会去解析并从那里下载,然后将数据插入本地数据库。

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

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 

回答

0

我张贴的结果帮人的人可能会希望将数据从一个解析服务器传输到本地数据库的过这个问题,在我的情况下SQLite。

我不需要在调用insertToSQLite func之前完成下载,而​​只需要在查询调用中添加insertToSQLite func。

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

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) 
} 
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. 
} 
+0

嗨贾斯汀,谢谢,但没有完全解决它。请参阅上文中的修改。 –