Варианты приведения типов в Swift: как? Типа, или как! Типа?



учитывая следующее в Swift:



var optionalString: String?
let dict = NSDictionary()


в чем практическая разница между следующими двумя утверждениями:



optionalString = dict.objectForKey("SomeKey") as? String


vs



optionalString = dict.objectForKey("SomeKey") as! String?
767   9  

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 } // false

Swift 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 дела

  1. считаем:

    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 или нет (вопросительный знак приходит, когда мы не знаем вещи.)

  2. сравните это с:

    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."

см.: https://developer.apple.com/swift/blog/?id=23

Я новичок в 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! String

vs

(2) : obj.lastName = obj.lName as? String

Ans : (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

    Ничего не найдено.