Firebase Swift 3数据库在setValue withCompletionBlock上崩溃

Ema*_*kan 8 ios firebase swift firebase-realtime-database swift3

我在iOS上使用Firebase和Swift 3.

我用的时候

FIRDatabase.database().reference().child("child").setValue("value") { 
  (error: Error?, databaseReference: FIRDatabaseReference) in
    print("Error while setting value \(error)")
}   
Run Code Online (Sandbox Code Playgroud)

应用程序在运行时使用以下日志崩溃:

***由于未捕获的异常'InvalidFirebaseData'终止应用程序,原因:'(nodeFrom:priority :)无法存储_SwiftValue类型的对象.只能存储NSNumber,NSString,NSDictionary和NSArray类型的对象.

我尝试使用相同的功能,但没有尾随闭包,出于某种原因,它的工作原理!

FIRDatabase.database().reference().child("child").setValue("value", 
  withCompletionBlock: { 
    (error: Error?, databaseReference: FIRDatabaseReference) in
      print("Error while setting value \(error)")
})
Run Code Online (Sandbox Code Playgroud)

关于尾随闭包和Swift 3有什么特别之处吗?

mdi*_*mer 8

tl; dr:Firebase提供了一个setValue(_ value: Any?, andPriority priority: Any?)在使用尾随闭包时不正确匹配的setValue(_ value: Any?, withCompletionBlock: (Error?, FIRDatabaseReference) -> Void).

解决方案:使用具有多种变体的API时,请避免使用尾随闭包.在这种情况下,更喜欢setValue(myValue, withCompletionBlock: { (error, dbref) in /* ... */ }); 千万不能使用setValue(myValue) { (error, dbref) in /* ... */ }.

说明

这似乎是一个Swift错误.与其他语言(如Java)一样,Swift通常会选择最具体的重载.例如,

class Alpha {}
class Beta : Alpha {}

class Charlie {
    func charlie(a: Alpha) {
        print("\(#function)Alpha")
    }
    func charlie(a: Beta) {
        print("\(#function)Beta")
    }
}

Charlie().charlie(a: Alpha()) // outputs: charlie(a:)Alpha
Charlie().charlie(a: Beta() as Alpha) // outputs: charlie(a:)Alpha
Charlie().charlie(a: Beta()) // outputs: charlie(a:)Beta
Run Code Online (Sandbox Code Playgroud)

但是,当重载函数与尾随闭包匹配时,Swift(至少有时)选择更通用的类型.例如,

class Foo {
    func foo(completion: () -> Void) {
        print(#function)
    }
    func foo(any: Any?) {
        print(#function)
    }
}

func bar() {}
Foo().foo(completion: bar) // outputs: foo(completion:)
Foo().foo(any: bar) // outputs: foo(any:)
Foo().foo() { () in } // outputs: foo(any:)
// ^---- Here lies the problem
// Foo().foo(bar) will not compile; can't choose between overrides.
Run Code Online (Sandbox Code Playgroud)

Any?是一种比一般更普遍的类型() -> Void- 即"任何东西,甚至是空"比"接收0参数并返回类型的函数"更广泛Void.但是,尾随封闭匹配Any?; 这与您对匹配最具体类型的语言的期望相反.