Быстрое литье / нисходящее литье

Почему проект шаблона игры Sprite Kit Game, созданный Xcode, использует as!:

if let sceneNode = scene.rootNode as! GameScene? {...}

Разве следующее не будет одинаково хорошо?

if let sceneNode = scene.rootNode as? GameScene {...}

Обратите внимание, что это не стандартный вопрос «в чем разница между as? и as!». И Downcasting options в Swift: как? Типа, или как! Тип? очень близок, но это не совсем одно и то же. Вопрос в том, что два приведенных выше паттерна кажутся функционально похожими (они оба приводятся вниз и разворачиваются), но непонятно, почему автор использовал if let ... as! GameScene? { ... } вместо более распространенного и естественного if let ... as? GameScene { ... }.


person Stephenye    schedule 11.02.2018    source источник
comment
спасибо Роб. Но в данном случае у него есть if, и это Bar? (а не Bar). Когда я смотрю на повторяющийся вопрос, ответ также говорит, что as! следует использовать только тогда, когда вы знаете, что понижение не подведет (это, конечно, имеет смысл). Итак, насколько я понимаю, as! Type? не добавляет больше преимуществ по сравнению с as? Type практически (в этом операторе if as! Type? можно заменить на as? Type, и, вероятно, это безопаснее)   -  person Stephenye    schedule 11.02.2018
comment
Может это просто ошибка? Я подозреваю, что компилятор в конце концов сделает это незаконным. Мне кажется, что шаблон был переведен с Objective-C на Swift кем-то, кто не совсем понимал, что делает.   -  person matt    schedule 11.02.2018


Ответы (2)


Эти два шаблона очень близки, но технически не одинаковы:

  • if let ... as! GameScene? {...} выполняет принудительное приведение к GameScene?, а if let затем безопасно разворачивает результирующий необязательный элемент.

  • if let ... as? GameScene { ... } изящно опустит и развернет результат.

Функционально эти два почти эквивалентны. Вопрос в том, почему шаблон будет использовать прежний синтаксис. Можно возразить, что шаблон as? немного двусмыслен, потому что, взглянув на код, вы не можете сказать, проверяете ли вы просто успешность приведения вниз или имеете дело также и с необязательным. Код шаблона делает это более явным.

Учитывая все вышесказанное, я бы использовал шаблон if let ... as? GameScene { ... }. Это обычное дело.

person Rob    schedule 11.02.2018
comment
Спасибо @Роб. Я еще раз взглянул на код для rootNode, и он имеет тип GKSceneRootNodeType, и документ говорит, что протокол GKSceneRootNodeType является косвенным типом для классов игровых сцен, которые может загружать класс GKScene. SKScene — единственный класс, который в настоящее время поддерживается для загрузки с классом GKScene. (GameScene является подклассом GKScene). Так что я предполагаю, что другой способ интерпретировать это так: код шаблона говорит, что он должен быть (as!) типа GKScene. Тем не менее, через несколько строк у него есть if let view = self.view as! SKView? { ... }, что не может быть объяснено таким образом. - person Stephenye; 11.02.2018
comment
Сказав все это, я согласен, что if let ... as? Type {...} эквивалентен и предпочтительнее. - person Stephenye; 11.02.2018

Я бы сказал, что это ошибка. В любом случае шаблон if let x = y as! Type? не нужен и не стоит его имитировать. Паттерн if let x = y as? Type является эквивалентным и обычным.

person matt    schedule 11.02.2018
comment
Спасибо @мат. Может быть, или, возможно, автор считает, что эти два шаблона незначительно отличаются. Несмотря на это, я согласен, что шаблон if let ... as? Type эквивалентен и предпочтительнее. - person Stephenye; 11.02.2018
comment
К сожалению, собственный шаблон/образец кода Apple часто не соответствует передовым методам. - person matt; 11.02.2018