[swift] 스위프트의 다운 캐스팅 옵션 : as? 입력 또는 as! 유형?

Swift에서 다음을 감안할 때 :

var optionalString: String?
let dict = NSDictionary()

다음 두 진술의 실질적인 차이점은 무엇입니까?

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

vs

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



답변

실제적인 차이점은 다음과 같습니다.

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)
}


답변

as? Types-다운 캐스팅 공정이 선택 사항임을 의미합니다. 프로세스는 성공하거나 실패 할 수 있습니다 (다운 캐스팅이 실패하면 시스템이 nil을 반환합니다).

as! Type?-여기서 다운 캐스팅 과정이 성공적이어야합니다 !. 끝 물음표는 최종 결과가 nil 일 수 있는지 여부를 나타냅니다.

“!”에 대한 추가 정보 그리고 “?”

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. 

    여기서 우리는 컴파일러에게 다운 캐스팅이 성공해야한다고 알려줍니다. 실패하면 시스템이 충돌합니다. 따라서 !값이 nil이 아니라고 확신 할 때 제공 합니다.


답변

vacawama가 말한 것을 명확히하기 위해 여기에 예가 있습니다 …

스위프트 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

스위프트 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 업 캐스팅 및 브리지 유형에 대한 유형 캐스팅에 사용
  • as? 안전한 캐스팅에 사용, 실패하면 nil 반환
  • 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

추가하여 ? 데이터 유형 바로 뒤에 컴파일러에게 변수에 숫자가 포함될 수 있는지 여부를 알립니다. 산뜻한! Optional 상수를 정의하는 것은 실제로 의미가 없습니다. 값을 한 번만 설정할 수 있으므로 값이 nil인지 여부를 말할 수 있습니다.

“?”를 사용해야하는 경우 그리고 언제 “!”

UIKit 기반의 간단한 앱이 있다고 가정 해 보겠습니다. 뷰 컨트롤러에 코드가 있고 그 위에 새로운 뷰 컨트롤러를 표시하려고합니다. 내비게이션 컨트롤러를 사용하여 화면에 새보기를 푸시하기로 결정해야합니다.

우리가 알고 있듯이 모든 ViewController 인스턴스에는 속성 탐색 컨트롤러가 있습니다. 탐색 컨트롤러 기반 앱을 빌드하는 경우 앱 마스터보기 컨트롤러의이 속성이 자동으로 설정되며이를 사용하여보기 컨트롤러를 푸시하거나 팝할 수 있습니다. 단일 앱 프로젝트 템플릿을 사용하는 경우 자동으로 생성되는 탐색 컨트롤러가 없으므로 앱의 기본 뷰 컨트롤러는 navigationController 속성에 아무것도 저장하지 않습니다.

이것이 바로 Optional 데이터 유형의 경우라고 이미 짐작 하셨을 것입니다. UIViewController를 확인하면 속성이 다음과 같이 정의되어 있음을 알 수 있습니다.

var navigationController: UINavigationController? { get }

이제 사용 사례로 돌아가 보겠습니다. 뷰 컨트롤러에 항상 내비게이션 컨트롤러가 있다는 사실을 알고 있다면 계속 진행하여 강제로 풀 수 있습니다.

controller.navigationController!.pushViewController(myViewController, animated: true)

당신은! 속성 이름 뒤에는 컴파일러 에게이 속성이 선택 사항인지 신경 쓰지 않는다고 말합니다.이 코드가 실행될 때 항상 값 저장소가 있으므로이 옵션을 일반 데이터 유형처럼 취급합니다. 좋지 않나요? 뷰 컨트롤러에 내비게이션 컨트롤러가 없다면 어떻게 될까요? navigationController에 저장된 값이 항상 있다는 제안이 잘못 되었습니까? 앱이 충돌합니다. 그렇게 간단하고 추합니다.

따라서! 이것이 안전하다고 101 % 확신하는 경우에만.

내비게이션 컨트롤러가 항상 있다는 확신이 없다면 어떨까요? 그런 다음 사용할 수 있습니까? 대신! :

controller.navigationController?.pushViewController(myViewController, animated: true)

무엇입니까? 속성 이름 뒤에는 컴파일러 에게이 속성에 nil 또는 값이 포함되어 있는지 여부를 알 수 없으므로 값이 있으면 사용하고 그렇지 않으면 전체 표현식 nil을 고려합니다. 효과적으로? 탐색 컨트롤러가있는 경우에만 해당 속성을 사용할 수 있습니다. 어떤 종류의 수표 나 어떤 종류의 주물이든 아니오. 이 구문은 내비게이션 컨트롤러가 있든 없든 상관하지 않고있을 때만 무언가를하고 싶을 때 완벽합니다.

Fantageek 에게 큰 감사


답변

그들은 Swift에서 두 가지 다른 형태의 다운 캐스팅 입니다.

as?조건부 형식 으로 알려진 ( ) 는 다운 캐스트하려는 유형의 선택적 값을 반환합니다.

다운 캐스트가 성공할지 확실하지 않을 때 사용할 수 있습니다. 이 형식의 연산자는 항상 선택적 값을 반환하며 다운 캐스트가 불가능한 경우 값은 nil이됩니다. 이를 통해 성공적인 다운 캐스트를 확인할 수 있습니다.


as!Forced Form 으로 알려진 ( ) 은 다운 캐스트를 시도하고 결과를 단일 복합 동작으로 강제 해제합니다.

다운 캐스트가 항상 성공할 것이라고 확신 할 때만 사용해야합니다 . 이 형식의 연산자는 잘못된 클래스 유형으로 다운 캐스트하려고하면 런타임 오류 를 트리거합니다 .

자세한 내용 은 Apple 문서의 Type Casting 섹션을 확인하십시오 .


답변

이 코드 예제는 누군가가 원칙을 이해하는 데 도움이 될 것입니다.

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 일 수 있음을 의미합니다.

이 관련 질문에서 더 많은 정보를 찾을 수 있습니다.