首页 > 解决方案 > Swift忽略块签名中定义的参数类型

问题描述

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

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在块签名中定义了类型,我就会在返回行上得到一个错误:

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 类型?

标签: swiftnspredicateswift-blockswift-optionals

解决方案


如果您查看签名NSPredicate.init(block:)您将看到该块接受两个参数并返回一个布尔值:(Any?, [String : Any]?) -> Bool)并且第一个参数确实是一个Any.

在您的第一个示例中,您强制强制转换,as!这就是它起作用的原因(如果类型实际上没有Paint装箱,它会在这里崩溃Any。您的第二个示例给您一个错误,因为您的类型注释是错误的;编译器需要第一个参数是Any而不是Paint?;它确实应该在上面的行中给您错误,但它似乎首先在返回的行上捕获它。

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

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
}

推荐阅读