Swift函数在应用程序中工作,但不在重写func viewDidLoad()

在我的iOS应用程序中,我有两个我想在viewDidLoad()中调用的与Firebase相关的函数。 第一个用.queryOrderedByKey()挑选一个随机的孩子, .queryOrderedByKey()孩子的密钥输出为一个string。 第二个使用该键和observeEventType来检索子值并将其存储在字典中。 当我用我的用户界面中的button触发这些function,他们按预期工作。

但是,当我把这两个函数内viewDidLoad(),我得到这个错误:

由于未捕获的exception“InvalidPathValidation”而终止应用程序,原因:'(child :)必须是非空string,不包含'。' '#''$''['或']''

有问题的代码行在我的AppDelegate.swift中,用红色突出显示:

class AppDelegate: UIResponder, UIApplicationDelegate, UITextFieldDelegate

当我注释掉第二个函数并在viewDidLoad中留下第一个函数时,应用程序加载正常,并且随后调用这两个函数(由button操作触发)按预期工作。

我在第一个函数的末尾添加了一行以打印出URLstring,并且没有任何违规字符: https://mydomain.firebaseio.com/myStuff/-KO_iaQNa-bIZpqe5xlghttps://mydomain.firebaseio.com/myStuff/-KO_iaQNa-bIZpqe5xlg

我还在viewDidLoad中的函数之间添加了一行来硬编码string,并且遇到了同样的InvalidPathException问题。

这是我的viewDidLoad()函数:

 override func viewDidLoad() { super.viewDidLoad() let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.dismissKeyboard)) view.addGestureRecognizer(tap) pickRandomChild() getChildValues() } 

这是第一个function:

 func pickRandomChild () -> String { var movieCount = 0 movieRef.queryOrderedByKey().observeEventType(.Value, withBlock: { (snapshot) in for movie in snapshot.children { let movies = movie as! FIRDataSnapshot movieCount = Int(movies.childrenCount) movieIDArray.append(movies.key) } repeat { randomIndex = Int(arc4random_uniform(UInt32(movieCount))) } while excludeIndex.contains(randomIndex) movieToGuess = movieIDArray[randomIndex] excludeIndex.append(randomIndex) if excludeIndex.count == movieIDArray.count { excludeIndex = [Int]() } let arrayLength = movieIDArray.count }) return movieToGuess } 

这是第二个function:

 func getChildValues() -> [String : AnyObject] { let movieToGuessRef = movieRef.ref.child(movieToGuess) movieToGuessRef.observeEventType(.Value, withBlock: { (snapshot) in movieDict = snapshot.value as! [String : AnyObject] var plot = movieDict["plot"] as! String self.moviePlot.text = plot movieValue = movieDict["points"] as! Int }) return movieDict ) 

好的措施,这是我的AppDelegate.swift的相关部分:

 import UIKit import Firebase @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, UITextFieldDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { FIRApp.configure() return true } 

我猜Swift正在执行的代码不是我所期望的顺序。 在运行第二个函数之前,Swift不会自动等待第一个函数完成吗? 如果是这样的话,为什么这个配对在应用程序的其他地方工作,而不是在viewDidLoad?

编辑:问题是闭包不按顺序调用。

我不确定你的pickRandomChild()和getChildValues()方法是什么,所以请将它们发布,但是我解决这个types问题的方式是通过可以在你的ViewController中调用的闭包发送数据。

例如,当我想要获取全名和行业的数据时,我使用了这个。 此方法采用Firebase用户,并包含完成后将调用的闭包。 这是专门用于拉取数据的类。

 func grabDataDict(fromUser user: FIRUser, completion: (data: [String: String]) -> ()) { var myData = [String: String]() let uid = user.uid let ref = Constants.References.users.child(uid) ref.observeEventType(.Value) { (snapshot, error) in if error != nil { ErrorHandling.defaultErrorHandler(NSError.init(coder: NSCoder())!) return } let fullName = snapshot.value!["fullName"] as! String let industry = snapshot.value!["industry"] as! String myData["fullName"] = fullName myData["industry"] = industry completion(data: myData) } } 

然后,我在Viewcontroller中定义了一个空string数组,并调用该方法,将variables设置为闭包内的数据。

 messages.grabRecentSenderIds(fromUser: currentUser!) { (userIds) in self.userIds = userIds print(self.userIds) } 

如果你发布你的方法,但是我可以帮你具体的。

编辑:固定的方法

1。

 func pickRandomChild (completion: (movieToGuess: String) -> ()) { var movieCount = 0 movieRef.queryOrderedByKey().observeEventType(.Value, withBlock: { (snapshot) in for movie in snapshot.children { let movies = movie as! FIRDataSnapshot movieCount = Int(movies.childrenCount) movieIDArray.append(movies.key) } repeat { randomIndex = Int(arc4random_uniform(UInt32(movieCount))) } while excludeIndex.contains(randomIndex) movieToGuess = movieIDArray[randomIndex] excludeIndex.append(randomIndex) if excludeIndex.count == movieIDArray.count { excludeIndex = [Int]() } let arrayLength = movieIDArray.count // Put whatever you want to return here. completion(movieToGuess) }) } 

2。

 func getChildValues(completion: (movieDict: [String: AnyObject]) -> ()) { let movieToGuessRef = movieRef.ref.child(movieToGuess) movieToGuessRef.observeEventType(.Value, withBlock: { (snapshot) in movieDict = snapshot.value as! [String : AnyObject] var plot = movieDict["plot"] as! String self.moviePlot.text = plot movieValue = movieDict["points"] as! Int // Put whatever you want to return here. completion(movieDict) }) } 

在某些模型类中定义这些方法,并且在viewcontroller中调用它们时,应该能够在每个闭包内部将View Controllervariables设置为movieDict和movieToGuess。 我在操场上做了这些,所以如果你有任何的错误,请告诉我。

你的函数pickRandomChild()getChildValues()是asynchronous的,所以它们只能在后面执行,所以如果getChildValues()需要pickRandomChild()的结果,应该在pickRandomChild()的完成处理程序/委托callback相反,因为当其中一个被调用,保证了function已经完成。

它在你注释掉第二个函数的时候起作用,并且只是按下button来触发它,因为在app加载和你按下asynchronouspickRandomChild()的button之间有足够的时间完全执行它的操作,允许getChildValues()使用它的请求返回值。