Swift 忽略块签名中定义的参数类型

Swift ignoring parameter types defined in block signature

我有下面的代码,编译器很满意:

func CheckPaintExists(colorCode : String, applicationCode : String) {
    let checkRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Paint")
    checkRequest.predicate = NSPredicate(block: { (item, bindings) -> Bool in
        return (item as! Paint).ColorCode == colorCode 
            && (item as! Paint).ApplicationCode == applicationCode
    })
    checkRequest.includesSubentities = false;

    //managedContext.count(for: ...)do further stuff
}

但是一旦我在块签名中定义了 item 类型,我在 return 行上得到一个错误:

func CheckPaintExists2(colorCode : String, applicationCode : String) {
    let checkRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Paint")
    checkRequest.predicate = NSPredicate(block: { (item : Paint?, bindings : NSDictionary?) -> Bool in
        return item.ColorCode == colorCode //*Value of type 'Any?' has no member 'ColorCode'
            && item.ApplicationCode == applicationCode
    })
    checkRequest.includesSubentities = false;

    //managedContext.count(for: ...)do further stuff
}

它说 Value of type 'Any?' has no member 'ColorCode'。我该如何解决这个问题?为什么它仍然使用块提供的默认 Any 类型?

如果你查看 NSPredicate.init(block:)signature 那么你会看到该块有两个参数并且 return 是一个布尔值:(Any?, [String : Any]?) -> Bool) 而第一个参数确实是一个 Any.

在您的第一个示例中,您使用 as! 进行强制转换,这就是它起作用的原因(如果类型实际上不是 Paint 装在 Any 中,它会在这里崩溃。你的第二个例子给你一个错误,因为你的类型注释是错误的;编译器期望第一个参数是 Any 而不是 Paint?;它确实应该给你上面一行的错误,但看起来它首先在 return.

线上捕获它

如果你想安全地打开它应该是:

func CheckPaintExists(colorCode : String, applicationCode : String) {
    let checkRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Paint")
    checkRequest.predicate = NSPredicate(block: { (item, bindings) -> Bool in
        guard let paint = item as? Paint else {
           return false
        }
        return paint.ColorCode == colorCode 
            && paint.ApplicationCode == applicationCode
    })
    checkRequest.includesSubentities = false;

    //managedContext.count(for: ...)do further stuff
}