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

标签 ios swift xcode

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

var DB : DatabaseQueue!

在同一个文件中,我提供了一个用于将上述对象连接到 SQLite 数据库的函数,该函数在应用程序开始运行时调用。我能够在我的一个 Controller 中使用它而不会出现任何问题(例如,该应用程序使用我连接到它的数据库运行时没有问题),如下所示:

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

但是,在另一个 Controller 中,相同的构造会遇到错误,

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

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

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
}

任何帮助将不胜感激!

最佳答案

当您在 Swift 中遇到泛型类型问题时,通常会遇到这种情况,错误消息没有任何帮助。

真正的问题是:

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

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

  3. 您的程序没有显式指定类型 T 或以其他方式提供让 Swift 推导出具体类型的约束。

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

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

由于DB是一个隐式解包的 optional ,类型检查器会通过(正如您可能猜到的那样)自动解包它来特殊处理它如果这样做会使语句类型 -检查语句何时进行类型检查。在所有其他方面,DB 的类型只是普通的DatabaseQueue?,一个常规的Optional

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

由于 DatabaseQueue? 没有 write 方法(因为 Optional 没有 write方法),调用DB.write是错误的。所以 Swift 想要打印一条错误消息。但它“有帮助地”看到包装类型 DatabaseQueue 确实有一个 write 方法。此时它已经完全忘记了 DB 被声明为隐式解包。因此,它告诉您解开 DB 以获取 write 方法,即使如果没有遇到另一个,它会自动完成此操作此语句有错误。

所以无论如何,您需要告诉 Swift T 使用什么类型。我怀疑你想说的是:

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

DB.write 调用的结果分配给外部 locsCountInFloor 足以修复错误,因为您已经显式定义了 locsCountInFloor< 的类型。由此,Swift 可以推断出对 DB.write 的调用的返回类型,并从中推断出闭包的类型。

关于ios - 使用 Xcode、Swift 和 GRDB,为什么我必须解开 DatabaseQueue?在我可以使用它的方法之前?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54478293/

相关文章:

ios - ionic ios 应用程序开发

iphone - 如何使用stringWithFormat将连字符动态添加到我的字符串中

ios - Swift 进度条completedUnitCount 和totalUnitCount

ios - 如何将字符串日期和时间格式化为2012年12月4日星期二下午5:30

ios - 从 Push Extension 到 App 触发 KVO

ios - 如何在 swiftUI 中创建一个普通 View

xcode - 在 Swift 中从 NSString 创建 NSData

iphone - 如何在 Xcode 4.2 中添加 entitlements.plist?

ios - 从代码 iOS 中删除相机胶卷中的图像

ios - 滚动到表格底部时如何添加 "Load more"页面