ios - Swift 函数在应用程序中有效,但在 override func viewDidLoad() 中无效

标签 ios swift firebase firebase-realtime-database

在我的 iOS 应用中,我有两个与 Firebase 相关的函数,我想在 viewDidLoad() 中调用它们。第一个使用 .queryOrderedByKey() 选择一个随机子项,并将子项的 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 User,并包含一个将在完成时调用的闭包。这是在专门用于提取数据的类中定义的。

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/45261458/

相关文章:

ios - 将UIPasteboard内容粘贴到其他应用程序中

ios - 当键盘存在时如何使 UITextField 向上移动 - 开始编辑?

ios - 有没有办法在发送本地通知时运行一些代码?

ios - 不能在属性初始值设定项中使用实例成员

angular - 在 AngularFire 和 Angularjs 2 中编写路由守卫以等待身份验证

angular - 如何从 Observable 正确读取一次数据后取消订阅

ios - 如何在 UICollectionView performBatchUpdates block 中对移动、插入、删除和更新进行排序?

ios - 检索使用 JSQMessage 发送的图像

swift - 'RLMException',原因 : 'Opening Realm files of format version 11 is not supported by this version of Realm'

Firebase 部署出现大量错误