Answers:
实际的区别是:
var optionalString = dict["SomeKey"] as? String
optionalString
将是类型的变量String?
。如果基础类型不是a,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?
-此处的向下浇铸过程应该成功(!
表示)。结尾的问号指示最终结果是否可以为零。
有关“!”的更多信息 和“?”
让我们拿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
}
因此,让我们像这样记住它-如果?
这意味着我们不确定值是否为零(当我们不知道事物时会出现问号)。
与此相反:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell.
在这里,我们告诉编译器向下转换应该成功。如果失败,系统将崩溃。因此,!
当我们确定值不为零时,我们给出。
为了澄清vacawama所说的,这是一个示例...
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
intNil as! String? // ==nil
不引起碰撞!!! ???,作为可选<Int>区域.None是从可选<字符串> .None不同
as?
到String
?为什么不将其转换为String?
?你为什么不垂头丧气as!
来String
?
Any
代替AnyObject
as
用于up铸和铸型为桥接型as?
用于安全投放,如果失败则返回nilas!
用于强制投射,如果失败则崩溃注意:
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
通过添加?在数据类型之后,立即告诉编译器该变量可能包含数字或不包含数字。整齐!请注意,定义可选常量实际上没有任何意义-您只能设置一次其值,因此可以说出它们的值是否为nil。
假设我们有一个基于UIKit的简单应用程序。我们在视图控制器中有一些代码,并希望在其之上提供一个新的视图控制器。我们需要决定使用导航控制器在屏幕上推送新视图。
众所周知,每个ViewController实例都有一个属性导航控制器。如果要构建基于导航控制器的应用程序,则会自动设置应用程序主视图控制器的此属性,并且可以使用它来推送或弹出视图控制器。如果您使用单个应用程序项目模板,则不会为您自动创建导航控制器,因此您应用程序的默认视图控制器将不会在NavigationController属性中存储任何内容。
我确定您已经猜到这正是Optional数据类型的情况。如果检查UIViewController,您将看到该属性定义为:
var navigationController: UINavigationController? { get }
现在让我们回到用例。如果您知道视图控制器将始终具有导航控制器,则可以继续进行以下操作:
controller.navigationController!.pushViewController(myViewController, animated: true)
当你放!在属性名称的后面,您告诉编译器我不在乎此属性是可选的,我知道在执行此代码时始终会有一个值存储,因此请将此Optional视为普通数据类型。那不是很好吗?但是,如果您的视图控制器没有导航控制器,会发生什么情况?如果您建议将始终存在存储在navigationController中的值是错误的?您的应用将崩溃。那样简单又丑陋。
因此,使用!仅在您101%确信这是安全的情况下。
如果您不确定始终会有导航控制器怎么办?那你可以用吗?代替 !:
controller.navigationController?.pushViewController(myViewController, animated: true)
什么?属性名称后面的内容告诉编译器我不知道该属性是否包含nil或值,因此:如果它具有值,请使用它,否则仅考虑整个表达式nil。有效地?允许您在有导航控制器的情况下使用该属性。否,是否进行任何形式的检查或任何形式的铸件。当您不在乎是否有导航控制器,并且仅在有导航控制器时才想做某事时,此语法才是完美的。
非常感谢Fantageek
它们是两种不同形式的向下转换 Swift。
(as?
)(称为条件表单)返回您要向下转换到的类型的可选值。
当您不确定向下转换是否成功时,可以使用它。这种形式的运算符将始终返回可选值,如果无法向下转换,则该值将为nil。这使您能够检查下调是否成功。
(as!
)(已知为强制形式)尝试向下转换并强制将结果作为单个复合动作展开。
仅当确定向下转换将始终成功时,才应使用它。如果尝试向下转换为不正确的类类型,则此形式的运算符将触发运行时错误。
有关更多详细信息,请检查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中,最容易记住这些运算符的模式是:!
表示“这可能会陷阱”,而?
表示“这可能是零”。
我是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
与
(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"
etc。然后“obj.lastName”
将其设置为nil值。所以,没有崩溃(快乐:)