Какая разница между "как?", "Как!" И "как"?

Прежде чем перейти на Swift 1.2, я мог бы написать следующую строку:

if let width = imageDetails["width"] as Int?

Теперь он заставляет меня написать эту строку:

if let width = imageDetails["width"] as! Int?

Мой вопрос: если я вынужден написать его, как указано выше, не могу ли я просто написать код ниже, и он будет делать то же самое? Это даст мне тот же результат во всех значениях imageDetails?

if let width = imageDetails["width"] as Int

Ответ 1

В качестве ключевого слова as используется как upcasts, так и downcasts:

// Before Swift 1.2
var aView: UIView = someView()

var object = aView as NSObject // upcast 

var specificView = aView as UITableView // downcast

Взрыв, идущий от производного класса к базовому классу, может быть проверен во время компиляции и никогда не сработает.

Тем не менее, downcasts может завершиться неудачно, так как вы всегда можете быть уверены в конкретном классе. Если у вас есть UIView, возможно, это UITableView или, возможно, UIButton. Если ваш нисходящий идет к правильному типу - отлично! Но если вам не удастся указать неправильный тип, вы получите ошибку времени выполнения, и приложение выйдет из строя.

В Swift 1.2 downcasts должны быть либо необязательными, либо как? или "принудительный отказ" с помощью!. Если вы уверены в типе, то вы можете заставить актеры с помощью! аналогично тому, как вы будете использовать неявно-развернутый вариант:

// After Swift 1.2
var aView: UIView = someView()

var tableView = aView as! UITableView

Восклицательный знак абсолютно ясно говорит о том, что вы знаете, что делаете, и что у вас все шансы будут ужасно ошибочными, если вы случайно перепутали свои типы!

Как всегда, как? с необязательным связыванием - самый безопасный способ:

// This isn't new to Swift 1.2, but is still the safest way
var aView: UIView = someView()

if let tableView = aView as? UITableView {
  // do something with tableView
}

Получите это с сайта: ИСТОЧНИК

Ответ 2

as

В Swift 1.2 и более поздних версиях as может использоваться только для восходящего (или значения) и соответствия шаблону:

// 'as' for disambiguation
let width = 42 as CGFloat
let block = { x in x+1 } as Double -> Double
let something = 3 as Any?  // optional wrapper can also be added with 'as'


// 'as' for pattern matching
switch item {
case let obj as MyObject:
    // this code will be executed if item is of type MyObject
case let other as SomethingElse:
    // this code will be executed if item is of type SomethingElse
...
}

as?

Оператор условного оператора as? пытается выполнить преобразование, но возвращает nil, если он не может. Таким образом, его результат является необязательным.

let button = someView as? UIButton  // button type is 'UIButton?'

if let label = (superview as? MyView)?.titleLabel {
    // ...
}

as!

Оператор as! предназначен для принудительного преобразования типов.

Использовать принудительную форму оператора литья типа (as!), только если вы уверен, что downcast всегда будет успешным. Эта форма оператора вызовет ошибку времени выполнения, если вы попытаетесь перетащить в неправильный тип класса.

// 'as!' for forced conversion.
// NOT RECOMMENDED.
let buttons = subviews as! [UIButton]  // will crash if not all subviews are UIButton
let label = subviews.first as! UILabel

Ответ 3

Правильная идиома, которая должна делать именно то, что вы хотите (во всех версиях Swift, по крайней мере, вплоть до 1.2), является необязательным приложением as?.

if let width = imageDetails["width"] as? Int

Опциональный листинг возвращает необязательный (Int? в этом случае) и тестируется во время выполнения. Ваш исходный код, вероятно, заставил литье на необязательный тип.