Варианты приведения типов в Swift: как? Типа, или как! Типа?
учитывая следующее в Swift:
var optionalString: String?
let dict = NSDictionary()
в чем практическая разница между следующими двумя утверждениями:
optionalString = dict.objectForKey("SomeKey") as? String
vs
optionalString = dict.objectForKey("SomeKey") as! String?
9 ответов:
практическая разница заключается в следующем:
var optionalString = dict["SomeKey"] as? String
optionalStringбудет переменной типаString?. Если базовый тип является чем-то иным, чемStringэто будет безвредно просто назначитьnilк факультативному.var optionalString = dict["SomeKey"] as! String?это говорит, Я знаю это
String?. Это тоже приведет кoptionalStringтипString?,но он рухнет, если базовый тип является что-то другое.первый стиль затем используется с
if letчтобы безопасно развернуть дополнительно:if let string = dict["SomeKey"] as? String { // If I get here, I know that "SomeKey" is a valid key in the dictionary, I correctly // identified the type as String, and the value is now unwrapped and ready to use. In // this case "string" has the type "String". print(string) }
чтобы прояснить, что сказал вакавама, вот пример...
Swift 3.0:
import UIKit let str_value: Any = String("abc")! let strOpt_value: Any? = String("abc")! let strOpt_nil: Any? = (nil as String?) let int_value: Any = Int(1) let intOpt_value: Any? = Int(1) let intOpt_nil: Any? = (nil as Int?) // as String //str_value as String // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast? //strOpt_value as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast? //strOpt_nil as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast? //int_value as String // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast? //intOpt_value as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast? //intOpt_nil as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast? // as? String str_value as? String // == "abc" strOpt_value as? String // == "abc" strOpt_nil as? String // == nil int_value as? String // == nil intOpt_value as? String // == nil intOpt_nil as? String // == nil // as! String str_value as! String // == "abc" strOpt_value as! String // == "abc" //strOpt_nil as! String // Run-Time Error: unexpectedly found nil while unwrapping an Optional value. //int_value as! String // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'. //intOpt_value as! String // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'. //intOpt_nil as! String // Run-Time Error: unexpectedly found nil while unwrapping an Optional value. // as String? //str_value as String? // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion //strOpt_value as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast? //strOpt_nil as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast? //int_value as String? // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion //intOpt_value as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast? //intOpt_nil as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast? // as? String? //str_value as? String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?' strOpt_value as? String? // == "abc" strOpt_nil as? String? // == nil //int_value as? String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?' intOpt_value as? String? // == nil intOpt_nil as? String? // == nil // as! String? //str_value as! String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?' strOpt_value as! String? // == "abc" strOpt_nil as! String? // == nil //int_value as! String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?' //intOpt_value as! String? // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'. intOpt_nil as! String? // == nil // let _ = ... as String //if let _ = str_value as String { true } // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast? //if let _ = strOpt_value as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast? //if let _ = strOpt_nil as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast? //if let _ = int_value as String { true } // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast? //if let _ = intOpt_value as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast? //if let _ = intOpt_nil as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast? // let _ = ... as? String if let _ = str_value as? String { true } // true if let _ = strOpt_value as? String { true } // true if let _ = strOpt_nil as? String { true } // false if let _ = int_value as? String { true } // false if let _ = intOpt_value as? String { true } // false if let _ = intOpt_nil as? String { true } // false // let _ = ... as! String //if let _ = str_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String' //if let _ = strOpt_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String' //if let _ = strOpt_nil as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String' //if let _ = int_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String' //if let _ = intOpt_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String' //if let _ = intOpt_nil as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String' // let _ = ... as String? //if let _ = str_value as String? { true } // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion //if let _ = strOpt_value as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast? //if let _ = strOpt_nil as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast? //if let _ = int_value as String? { true } // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion //if let _ = intOpt_value as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast? //if let _ = intOpt_nil as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast? // let _ = ... as? String? //if let _ = str_value as? String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?' if let _ = strOpt_value as? String? { true } // true if let _ = strOpt_nil as? String? { true } // true //if let _ = int_value as? String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?' if let _ = intOpt_value as? String? { true } // false if let _ = intOpt_nil as? String? { true } // true // let _ = ... as! String? //if let _ = str_value as! String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?' if let _ = strOpt_value as! String? { true } // true if let _ = strOpt_nil as! String? { true } // false //if let _ = int_value as! String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?' //if let _ = intOpt_value as! String? { true } // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'. if let _ = intOpt_nil as! String? { true } // falseSwift 2.0:
import UIKit let str: AnyObject = String("abc") let strOpt: AnyObject? = String("abc") let strNil: AnyObject? = (nil as String?) let int: AnyObject = Int(1) let intOpt: AnyObject? = Int(1) let intNil: AnyObject? = (nil as Int?) str as? String // == "abc" strOpt as? String // == "abc" strNil as? String // == nil int as? String // == nil intOpt as? String // == nil intNil as? String // == nil str as! String? // Compile-Time Error: Cannot downcast from 'AnyObject' to a more optional type 'String?' strOpt as! String? // == "abc" strNil as! String? // == nil int as! String? // Compile-Time Error: Cannot downcast from 'AnyObject' to a more optional type 'String?' intOpt as! String? // Run-Time Error: Could not cast value of type '__NSCFNumber' to 'NSString' intNil as! String? // == nil
as? Types- означает процесс литья является обязательным. Процесс может быть успешным или нет(система возвращает nil, если вниз не литье).Любой способ не рухнет, если вниз кастинг не удается.
as! Type?- здесь процесс вниз бросать должен быть успешен (!указывает на то, что) . Конечный вопросительный знак указывает, может ли конечный результат быть равен нулю или нет.подробнее о "!"и "?"
давайте возьмем 2 дела
считаем:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCellздесь мы не знаем, является ли результат приведения ячейки с идентификатором "Cell" к UITableViewCell успешным или нет. Если неудачно, то он возвращает nil (так что мы избегаем аварии здесь). Здесь мы можем сделать, как показано ниже.
if let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell { // If we reached here it means the down casting was successful } else { // unsuccessful down casting }так давайте вспомним это так-если
?это означает, что мы не уверены, равно ли значение nil или нет (вопросительный знак приходит, когда мы не знаем вещи.)сравните это с:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell.здесь мы говорим компилятору, что кастинг должен быть успешным. Если это не удается, система рухнет. Поэтому мы даем
!когда мы уверены, что значение не ноль.
это две разные формы Downcasting в Swift.
(
as?), что на Условная Форма, возвращает необязательное значение типа, который вы пытаетесь понизить.Вы можете использовать его, когда вы не уверены, если потупив получится. Эта форма оператора всегда будет возвращать дополнительное значение, и значение будет равно нулю, если понижение невозможно. Это позволяет вам проверьте успешность понижения.
(
as!), что на Принудительная Форма, пытается понизить и принудительно разворачивает результат как одно составное действие.вы должны использовать только когда вы уверены, что потупее будет всегда получится. Такая форма оператора может вызвать во время выполнения ошибка если вы пытаетесь понизить до неправильного класса тип.
для более подробной информации, пожалуйста, проверьте Тип Литья раздел документации Apple.
asиспользуется для upcasting и тип литья до мостового типаas?используется для безопасного литья, возвращает ноль, если не удалосьas!используется для литья, аварии, если неПримечание:
as!не может привести необработанный тип к необязательномупримеры:
let rawString: AnyObject = "I love swift" let optionalString: AnyObject? = "we love swift" let nilString: AnyObject? = (nil as String?) let rawInt: AnyObject = Int(3) let optionalInt: AnyObject? = Int(3) let nilInt: AnyObject? = (nil as Int?)
пример
var age: Int? = nil var height: Int? = 180добавить ? сразу после того, как данные тип вы сообщаете компилятору, что переменная может содержать число или нет. Аккуратно! Обратите внимание, что на самом деле нет смысла определять необязательные константы – вы можете установить их значение только один раз, и поэтому вы сможете сказать, будет ли их значение равно нулю или нет.
когда мы должны использовать "?"и когда "!"
допустим, у нас есть простое приложение на основе UIKit. у нас есть некоторый код в нашем контроллере вида и хочет представить новый контроллер вида поверх него. и мы должны решите нажать новый вид на экране с помощью навигационного контроллера.
как мы знаем, каждый экземпляр ViewController имеет контроллер навигации свойств. Если вы создаете приложение на основе навигационного контроллера, это свойство контроллера главного вида вашего приложения устанавливается автоматически, и вы можете использовать его для нажатия или всплывания контроллеров вида. Если вы используете один шаблон проекта приложения – для вас не будет автоматически создан навигационный контроллер, поэтому контроллер представления вашего приложения по умолчанию будет в свойстве navigationController ничего не хранится.
я уверен, что вы уже догадались, что это именно случай для дополнительного типа данных. Если вы проверите UIViewController, вы увидите, что свойство определяется как:
var navigationController: UINavigationController? { get }Итак, давайте вернемся к нашему делу пользы. Если вы точно знаете, что ваш контроллер вида всегда будет иметь навигационный контроллер, вы можете пойти вперед и заставить его развернуть:
controller.navigationController!.pushViewController(myViewController, animated: true)когда вы ставите ! позади объекта недвижимости имя вы говорите компилятору мне все равно, что это свойство является необязательным, я знаю, что при выполнении этого кода всегда будет хранилище значений, поэтому рассматривайте это необязательное как обычный тип данных.
может быть, этот пример поможет кому-то понять принцип:
var dict = [Int:Any]() dict[1] = 15 let x = dict[1] as? String print(x) // nil because dict[1] is an Int dict[2] = "Yo" let z = dict[2] as! String? print(z) // optional("Yo") let zz = dict[1] as! String // crashes because a forced downcast fails let m = dict[3] as! String? print(m) // nil. the forced downcast succeeds, but dict[3] has no value
первый-это "условное приведение" (см. раздел "операторы приведения типов" в документации, которую я связал). Если приведение выполняется успешно, значение выражения оборачивается необязательным и возвращается, в противном случае возвращается значение nil.
второй означает, что optionalString может быть строковым объектом или это может быть nil.
более подробную информацию можно найти в этом соответствующем вопросе.
возможно, проще всего запомнить шаблон для этих операторов в Swift как:
!подразумевает "это может ловушка", в то время как?указывает, что "это может быть nil."
Я новичок в Swift и пишу этот пример, пытаясь объяснить, как я понимаю, о "optionals". Если я ошибаюсь, пожалуйста, поправьте меня.
спасибо.
class Optional { var lName:AnyObject! = "1" var lastName:String! } let obj = Optional() print(obj.lName) print(obj.lName!) obj.lastName = obj.lName as? String print(obj.lastName)
(1) :
obj.lastName = obj.lName as! Stringvs
(2) :
obj.lastName = obj.lName as? StringAns : (1) здесь программист чертовски уверен, что
“obj.lName”содержит объект строкового типа. Так что просто дайте это значение“obj.lastName”.теперь, если программист прав, значит
"obj.lName"is строковый тип объекта, то нет проблем. "параметр obj.lastName " будет иметь то же значение.но если программист ошибается значит
"obj.lName"не является объектом типа string, т. е. он содержит объект другого типа, например "NSNumber" и т. д. Затем сбой (ошибка времени выполнения).(2) программист не уверен, что
“obj.lName”содержит объект типа string или любой другой объект типа. Поэтому установите это значение в“obj.lastName”если это строковый тип.теперь, если программист прав, значит
“obj.lName”- строка введите объект, то нет проблем.“obj.lastName”будет установлено то же значение.но если программист ошибается, значит obj.lName не является объектом строкового типа, т. е. он содержит какой-либо другой объект типа, например
"NSNumber"etc. Тогда“obj.lastName”будет установлено значение nil. Итак, Никакой Аварии (Happy:)
Comments