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 가지 사례를 보자
-
치다:
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.
여기서 우리는 컴파일러에게 다운 캐스팅이 성공해야한다고 알려줍니다. 실패하면 시스템이 충돌합니다. 따라서
!
값이 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 일 수 있음을 의미합니다.
이 관련 질문에서 더 많은 정보를 찾을 수 있습니다.