Связанное значение в условной привязке должно иметь необязательный тип

У меня есть протокол, определенный:

protocol Usable {
    func use()
}

и класс, который соответствует этому протоколу

class Thing: Usable {
    func use () {
        println ("you use the thing")
    }
}

Я хотел бы программно проверить, соответствует ли класс Thing используемому протоколу.

let thing = Thing()

// Check whether or not a class is useable
if let usableThing = thing as Usable { // error here
    usableThing.use()
}
else {
    println("can't use that")
}

Но я получаю ошибку

Bound value in a conditional binding must be of Optional Type

Если я попробую

let thing:Thing? = Thing()

Я получаю ошибку

Cannot downcast from 'Thing?' to non-@objc protocol type 'Usable'

Я тогда добавляю @objc к протоколу и получите ошибку

Forced downcast in conditional binding produces non-optional type 'Usable'

В какой момент я добавляю ? после as, который, наконец, исправляет ошибку.

Как я могу достичь этой функциональности с помощью условного связывания с протоколом не @objc, так же, как и в "Advanced Swift" 2014 WWDC Video?

5 ответов

Решение

Вы можете получить его для компиляции, сделав приведение как Usable? вместо использования, как это:

// Check whether or not a class is useable
if let usableThing = thing as Usable? { // error here
    usableThing.use()
}
else {
    println("can't use that")
}

Это работает для меня на детской площадке

protocol Usable {
    func use()
}

class Thing: Usable {
    func use () {
        println ("you use the thing")
    }
}

let thing = Thing()
let testThing : AnyObject = thing as AnyObject

if let otherThing = testThing as? Thing {
    otherThing.use()
} else {
    println("can't use that")
}

Как упоминалось в документе Swift, is Оператор - это тот парень, который нужен вам для работы:

Оператор is во время выполнения проверяет, относится ли выражение к указанному типу. Если так, это возвращает истину; в противном случае возвращается false.

Проверка не должна быть известна как истинная или ложная во время компиляции.

Таким образом, следующий тест, как правило, будет то, что вам нужно:

if thing is Usable { 
    usableThing.use()
} else {
    println("can't use that")
}

Однако, как указывает документ, Swift может обнаружить во время компиляции, что выражение всегда истинно, и объявляет ошибку, чтобы помочь разработчику.

Вы получаете

Bound value in a conditional binding must be of Optional Type

так как thing as Usable должен возвращать необязательный тип, чтобы сделать его as? должен решить проблему. К сожалению, ошибка все еще сохраняется по какой-то странной причине. Во всяком случае, я нашел способ обойти это, чтобы извлечь присвоение переменной внутри оператора if

let thing = Thing()

let usableThing = thing as? Usable

if useableThing { 
    usableThing!.use()
}
else {
    println("can't use that")
}

Быстрые протоколы не работают в Playgrounds в первой бета-версии, вместо этого попробуйте построить реальный проект.

Другие вопросы по тегам