使用Xcode,Swift和GRDB,为什么必须解包DatabaseQueue?在我可以使用它的方法之前?

时间:2019-02-01 11:09:21

标签: ios swift xcode

我正在使用GRDB库将SQLite与我的iOS应用程序项目集成。我在AppDelegate.swift中声明了DatabaseQueue对象,如下所示:

var DB : DatabaseQueue!

在同一文件中,我提供了一个将上述对象连接到SQLite数据库的功能,该功能在应用程序开始运行时会调用。我已经能够在我的一个控制器中使用它,而不会出现问题(例如,应用程序在使用连接到它的数据库运行时没有问题),就像这样:

var building : Building?
do {
    try DB.write { db in
        let building = Building.fetchOne(db, "SELECT * FROM Building WHERE number = ?", arguments: [bldgNumber])
    }
} catch {
    print(error)
}

但是,在另一个控制器中,相同的构造遇到错误,

Value of optional type 'DatabaseQueue?' must be unwrapped to refer to member 'write' of wrapped base type 'DatabaseQueue'

唯一的区别(当然,除了代码之外)是do-catch块内有return语句,因为后者在函数(用于numberOfRowsInSection的tableView)内,该函数应该返回整数。错误的代码部分如下所示。

var locsCountInFloor : Int
do {
    try DB.write { db in
        if currentBuilding!.hasLGF == true {
            locsCountInFloor = IndoorLocation.filter(bldg == currentBuilding! && level == floor).fetchCount(db)
        } else {
            locsCountInFloor = IndoorLocation.filter(bldg == currentBuilding! && level == floor + 1).fetchCount(db)
        }
        return locsCountInFloor
    }
} catch {
    return 0
}

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

通常,当您在Swift中遇到泛型类型的问题时,错误消息没有帮助。

这是真正的问题:

  1. DB.write的参数和返回类型是通用的。它具有类型参数T。闭包参数的返回类型为T,而write方法本身返回T

  2. 您要传递的闭包不只是一个表达式。这是一个多语句闭包。 Swift不会从闭包中的语句推断出多语句闭包的类型。出于实际原因,这仅仅是编译器的一个局限。

  3. 您的程序未明确指定类型T或提供了其他约束,这些约束使Swift可以推断出具体类型。

程序的这些特征意味着Swift不知道T使用的具体类型。因此,编译器的类型检查器/推断器将失败。您可能会收到有关此问题的错误消息。 (可能是一条难以理解的消息,但可能至少与之相关)。

但这不是您得到的,因为您将DB声明为DatabaseQueue!

由于DB是一个隐式解包的可选内容,因此类型检查器会通过自动地对其进行解包(您可能会猜到)来特别地处理它(如果这样做),当否则将进行类型检查。通过其他所有方式,DB的类型只是普通的DatabaseQueue?,是常规的Optional

在这种情况下,由于上述错误,即使使用自动展开,该语句也不会进行类型检查:Swift无法推断出具体类型来代替T。由于该语句不会以任何一种方式进行类型检查,因此Swift不会为您插入展开内容。然后它继续进行,就好像DB被声明为DatabaseQueue?

由于DatabaseQueue?没有write方法(因为Optional没有write方法),所以呼叫DB.write是错误的。因此,Swift想打印一条错误消息。但是它“有帮助”地看到包装类型DatabaseQueue 确实具有一种write方法。至此,它已经完全忘记了DB被声明为隐式解包。因此,它告诉您打开DB进入write方法,即使,即使在此语句中没有遇到其他错误,它也会自动完成。< / p>

因此,无论如何,您需要告诉Swift T使用哪种类型。我怀疑您是想这样说:

var locsCountInFloor: Int
do {
    locsCountInFloor = try DB.write { db in
        ...

DB.write调用的结果分配给外部locsCountInFloor就足以解决该错误,因为您已经明确定义了locsCountInFloor的类型。由此,Swift可以推断出对DB.write的调用的返回类型,以及闭包的类型。