了解Swift的关闭类型要求

时间:2015-04-01 00:52:05

标签: 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? { get }

我在这里错过了什么与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上收到错误:Cannot invoke 'map' with an argument list of type '((_) -> _)'

我认为这样:

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

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

1 个答案:

答案 0 :(得分:1)

这些类型并不匹配。 createdAtOptionalcompare方法是非可选的。另外,如果不确切知道哪些下标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在对象上有{n}的可能性,您可能还希望有某种后备:

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