답변:
실제적인 차이점은 다음과 같습니다.
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
intNil as! String? // ==nil
. 크래시를 일으키지 않습니다 !!! ???, 옵션 <Int> .None은 Optional <String>
as?
에 String
? 왜 다운 캐스트하지 String?
않습니까? 왜 낙심하지 않습니다 as!
에 String
?
Any
대신 사용해야 합니다AnyObject
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 일 수 있음을 의미합니다.
이 관련 질문에서 더 많은 정보를 찾을 수 있습니다.
Swift에서 이러한 연산자의 패턴을 기억하는 것이 가장 쉬울 수 있습니다. !
"이것은 트랩 할 수 있습니다"를 ?
의미하고 "this might be nil "을 나타냅니다.
저는 Swift 초보자이며 '선택 사항'에 대해 이해하는대로 설명하려고이 예제를 작성합니다. 내가 틀렸다면 나를 바로 잡으십시오.
감사.
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
정답 : (1) 여기서 프로그래머는 “obj.lName”
문자열 유형 객체 를 포함 하고 있다고 확신 합니다. 따라서 그 값을 “obj.lastName”
.
이제 프로그래머가 옳다면 "obj.lName"
문자열 유형 객체를 의미하면 문제가 없습니다. "obj.lastName"은 동일한 값으로 설정됩니다.
그러나 프로그래머가 틀렸다면 "obj.lName"
문자열 유형 객체가 아니라는 것을 의미 합니다. 즉 "NSNumber"등과 같은 다른 유형 객체를 포함합니다. 그런 다음 CRASH (런타임 오류).
(2) 프로그래머는 “obj.lName”
문자열 유형 객체 또는 다른 유형 객체 가 포함되어 있는지 확신하지 못합니다 . 따라서 “obj.lastName”
문자열 유형이면 해당 값을로 설정하십시오 .
이제 프로그래머가 옳다면 “obj.lName”
문자열 유형 객체를 의미하면 문제가 없습니다. “obj.lastName”
동일한 값으로 설정됩니다.
그러나 프로그래머가 틀렸다면 obj.lName이 문자열 유형 객체가 아니라는 것을 의미합니다. 즉, 다른 유형 객체 "NSNumber"
등 이 포함되어 있습니다 . 그런 다음 “obj.lastName”
nil 값으로 설정됩니다. 그래서 크래시가 없습니다 (Happy :)