swift - 了解 Swift 的闭包类型要求

标签 swift closures

我正在努力养成以 Swifty 方式而不是翻译 Obj-C 的方式做事的习惯。

我正在用 Parse 做一个项目,在获取一堆 Parse 对象后,我想先对它们进行排序,然后从中提取特定的属性。这就是我现在正在尝试的:

if let notifications = fetchedObjects as? [PFObject] {
    // This line tells me "Cannot invoke 'sorted' with an argument list of type '((_, _) -> _)'
    let sortedMessages: [String] = notifications.sorted { $0.createdAt.compare($1.createdAt) == .OrderedAscending }
}

PFObject 有一个 createdAt 属性声明如下:var createdAt: NSDate? {获取}

我在这里遗漏了什么会扰乱 Swift 的类型检查?

在找出上述错误后,这是我想要的:

if let notifications = fetchedObjects as? [PFObject] {
    let sortedMessages: [String] = notifications.sorted({ $0.createdAt.compare($1.createdAt) == .OrderedAscending }).map { $0["message"] }
}

在我看来,所有类型都应该清晰且匹配。

更新

我今天又回到了这里,让它工作了。我没有在我的原始帖子中写它,但昨天我确实尝试强制打开 createdAt 可选的:

if let notifications = fetchedObjects as? [PFObject] {
    // This line tells me "Cannot invoke 'sorted' with an argument list of type '((_, _) -> _)'
    let sortedMessages: [String] = notifications.sorted { $0.createdAt!.compare($1.createdAt!) == .OrderedAscending }
}

这给了我完全相同的错误。到目前为止,我在使用 Swift 时学到的一件事是,当它给出神秘的类型不匹配错误时,最好为每个变量显式添加类型声明——这通常会导致更具体的错误消息。所以,今天,我把上面的代码写成这样:

    if let notifications = objects as? [PFObject] {
        let sortedMessages: [String] = notifications.sorted { (lhs: PFObject, rhs: PFObject) -> Bool in
            return rhs.createdAt!.compare(lhs.createdAt!) == .OrderedAscending
            }.map { $0["message"] as! String }
    }

这似乎编译没有问题。但是如果我依赖类型推断:

    if let notifications = objects as? [PFObject] {
        let sortedMessages: [String] = notifications.sorted { lhs, rhs in
            return rhs.createdAt!.compare(lhs.createdAt!) == .OrderedAscending
            }.map { $0["message"] as! String }
    }

我在 map 上遇到错误:无法使用类型为“((_) -> _)”的参数列表调用“map”

在我看来是这样的:

if let notifications = objects as? [PFObject] {
    let sortedMessages: [String] = notifications.sorted { $0.createdAt!.compare($1.createdAt!) == .OrderedAscending }
       .map { $0["message"] as! String }
}

应该是有效的,但是 Swift 的类型推断还没有达到标准……(?)。我不愿意让自己摆脱困境并责怪语言,但在这种情况下看起来很合理。我错过了什么吗?

最佳答案

类型不完全匹配。 createdAt 是一个Optional,而compare 方法接受一个非可选的。此外,如果不知道下标 PFObject 返回什么,如果它像字典,我猜它是 AnyObject!AnyObject?,其中情况下,它需要进行类型转换,并且可能需要使用 ! 强制解包。以下代码将编译:

notifications.sorted {
    switch ($0.createdAt, $1.createdAt) {
    case (.Some(let first), .Some(let second)):
        return first.compare(second) == .OrderedAscending
    default: 
        return true
    }
}.map { $0["message"]! as String }

请注意,在 Swift 1.2 中,您需要使用 as! 而不是 as,因为这是一个不安全的转换(来自 AnyObjectString)。如果对象上的 message 有可能为 nil,您可能还需要某种回退:

.map { $0["message"] as? String ?? "Default message" }

关于swift - 了解 Swift 的闭包类型要求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29381084/

相关文章:

Swift loadItem 关闭未运行

swift - 无法使用类型为 '' 的参数列表调用 ''

swift - 支持变种!?在协议(protocol)中

ios - Swift : Thread 1: EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP, 子代码=0x0) 发生错误

ios - Swift/如何填充 UITableViewCells

closures - 在 Swift 中调度闭包表达式

ios - 点击时按钮图像上的动画

javascript - 闭包 - JS Fiddle 和简单 HTML 文件上的不同行为

JavaScript 定义然后调用语法

grails - 如何用Groovy闭包包装所有Grails服务方法?