在我的 iOS 应用程序中,我想在 viewDidLoad() 中调用两个与 Firebase 相关的函数。第一个使用 .queryOrderedByKey()
随机选择一个 child ,并将 child 的 key 作为字符串输出。第二个使用该键和 observeEventType
检索子值并将其存储在字典中。当我使用 UI 中的按钮触发这些功能时,它们会按预期工作。
但是,当我将这两个函数都放在 viewDidLoad() 中时,我得到了这个错误:
Terminating app due to uncaught exception 'InvalidPathValidation', reason: '(child:) Must be a non-empty string and not contain '.' '#' '$' '[' or ']''
有问题的代码行在我的 AppDelegate.swift 中,以红色突出显示:
AppDelegate 类:UIResponder、UIApplicationDelegate、UITextFieldDelegate
当我注释掉第二个函数并将第一个保留在 viewDidLoad 中时,应用程序加载正常,并且两个函数的后续调用(由按钮操作触发)按预期工作。
我在第一个函数的末尾添加了一行来打印 URL 字符串,它没有任何违规字符:https://mydomain.firebaseio.com/myStuff/-KO_iaQNa-bIZpqe5xlg
我还在 viewDidLoad 中的函数之间添加了一行以对字符串进行硬编码,但我遇到了同样的 InvalidPathException 问题。
这是我的 viewDidLoad() 函数:
override func viewDidLoad() {
super.viewDidLoad()
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.dismissKeyboard))
view.addGestureRecognizer(tap)
pickRandomChild()
getChildValues()
}
这是第一个函数:
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
}
这是第二个函数:
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() 方法是什么,所以也请把它们贴出来,但我解决这个类型问题的方法是通过一个可以在你的 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 中定义了一个空字符串数组并调用了该方法,将变量设置为我在闭包内的数据。
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)
})
}
在某些模型类中定义这些方法,当您在 View Controller 中调用它们时,您应该能够在每个闭包内将 View Controller 变量设置为 movieDict 和 movieToGuess。我在 Playground 上制作了这些,所以如果您有任何错误,请告诉我。
关于ios - Swift 函数在应用程序中有效,但在 override func viewDidLoad() 中无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38820491/