Swift下行选项:作为? types,或作为! types?
在Swift中给出以下内容:
var optionalString: String? let dict = NSDictionary()
以下两种说法有什么实际区别:
optionalString = dict.objectForKey("SomeKey") as? String
VS
optionalString = dict.objectForKey("SomeKey") as! String?
实际区别是这样的:
var optionalString = dict.objectForKey("SomeKey") as? String
optionalString
将是一个String?
types的variablesString?
。 如果底层types是一个String
以外的东西,这将无害地只是分配给可选的nil
。
var optionalString = dict.objectForKey("SomeKey") as! String?
这说,我知道这个东西是一个String?
。 这也会导致optionalString
types为String?
, 但是如果底层的types是别的,它会崩溃。
第一种风格,然后使用, if let
安全解开可选:
if let string = dict.objectForKey("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". println(string) }
如? types – 表示向下铸造过程是可选的。 该过程可以成功或不成功(如果下注失败,则系统将返回nil)。如果下注失败,任何方式都不会崩溃。
如! types? – 这里的下注过程应该是成功的(“!”表示)。 最后的问号表示最终结果是否为零。
更多关于“!”的信息 和“?”
我们来看两个例子
1) let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
。
– 这里我们不知道是否将具有标识符“Cell”的单元格向下转换为UITableViewCell的结果是否成功。 如果不成功,则返回零(所以我们避免在这里崩溃)。 在这里,我们可以做如下给出。
if let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell { //If we reached here it means the down casting was successfull } else { // unsuccessful down casting }
所以让我们像这样记住 – 如果“?” 这意味着我们不确定价值是否为零(当我们不知道事情时,就会出现问号)。
2)
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
它们是Swift中两种不同forms的Downcasting 。
( as?
) ,这是知道的条件forms ,返回一个可选的值,你正试图向下转换的types。
当你不确定沮丧是否成功时,你可以使用它。 这种forms的操作符将始终返回一个可选值,如果downcast不可能,值将为零。 这使您能够检查一个成功的downcast。
( as!
) ,这是知道的强迫forms ,企图沮丧和强行解开结果作为一个单一的复合行动。
只有当你确定沮丧总会成功的时候,你才应该使用它。 如果尝试向下转换为不正确的类types,则此运算符forms将触发运行时错误 。
有关更多详细信息,请参阅Apple文档的types转换部分。
- 用于上传和types转换为桥接types
-
as?
用于安全铸造,如果失败则返回零 -
as!
用来强制铸造,失败时崩溃
注意:
-
as!
不能将原始types转换为可选项
例子:
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
通过添加一个? 在数据types之后立即告诉编译器该variables可能包含一个数字。 整齐! 注意定义可选常量没有什么意义 – 你只能设置一次它们的值,所以你可以说它们的值是否为零。
当我们应该使用“?” 什么时候 ”!”
假设我们有基于UIKit的简单应用程序。 我们在视图控制器中有一些代码,并希望在其上面呈现一个新的视图控制器。 我们需要决定使用导航控制器在屏幕上推新的视图。
我们知道每个ViewController实例都有一个属性导航控制器。 如果您正在构build基于导航控制器的应用程序,则应用程序主视图控制器的此属性会自动设置,您可以使用它来推送或popup视图控制器。 如果您使用单个应用程序项目模板 – 将不会为您自动创build导航控制器,因此您的应用程序的默认视图控制器将不会在navigationController属性中存储任何内容。
我相信你已经猜到,这是一个可选的数据types的情况。 如果您检查UIViewController,您会看到该属性被定义为:
var navigationController: UINavigationController? { get }
那么让我们回到我们的用例。 如果你知道一个事实,你的视图控制器将始终有一个导航控制器,你可以继续并强制解包:
controller.navigationController!.pushViewController(myViewController, animated: true)
当你把一个! 在属性名后面你告诉编译器我不在乎这个属性是否可选,我知道当这个代码执行的时候总是会有一个值存储区,所以把它当作普通的数据types来处理。 那不好吗? 如果没有导航控制器到您的视图控制器会发生什么? 如果你build议在navigationController中总会有一个存储的值是错误的? 你的应用程序将崩溃。 简单而丑陋的。
所以,用! 只有当你101%确定这是安全的。
如果你不确定总会有导航控制器,那么怎么样? 那你可以用吗? 代替 !:
controller.navigationController?.pushViewController(myViewController, animated: true)
什么? 在属性名称后面告诉编译器是我不知道这个属性是否包含nil或者一个值,所以:如果它有值使用它,并且oterwise只是考虑整个expression式nil。 有效的? 允许您在有导航控制器的情况下使用该属性。 没有,如果检查任何种类或任何forms的铸件。 当你不关心你是否有导航控制器,并且只有在有的时候才想做某事,这个语法是完美的。
非常感谢Fantageek
也许这个代码示例可以帮助别人理解这个原则:
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
第一个是“有条件的转换”(在我所链接的文档中查看“types转换运算符”) 。 如果转换成功,expression式的值被包装在一个可选的并返回的,否则返回的值是零。
第二种意思是说,optionalString可以是一个string对象,也可以是零。
在这个相关的问题find更多的信息 。
在Swift中记住这些运算符的模式可能是最简单的: !
暗示“这可能陷阱”,而?
表示“这可能是零”。
请参阅: 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
obj.lastName = obj.lName as! String
VS
(2): obj.lastName = obj.lName as? String
obj.lastName = obj.lName as? String
Ans:(1)这里程序员确定“obj.lName”
包含stringtypes的对象。 所以把这个值给“obj.lastName”
。
现在,如果程序员是正确的意思是"obj.lName"
是stringtypes的对象,那么没有问题。 “obj.lastName”将设置为相同的值。
但是,如果程序员是错误的意思是"obj.lName"
不是stringtypes的对象,即它包含一些其他types的对象,如“NSNumber”等,然后CRASH(运行时错误)。
(2)程序员不确定“obj.lName”
包含stringtypes对象或任何其他types的对象。 因此,如果它是stringtypes,则将该值设置为“obj.lastName”
。
现在,如果程序员是正确的意思是“obj.lName”
是stringtypes的对象,那么没有问题。 “obj.lastName”
将设置为相同的值。
但是,如果程序员错了意味着obj.lName不是stringtypes的对象,即它包含一些其他types的对象,如"NSNumber"
等,那么“obj.lastName”
将设置为零值。 所以,没有崩溃(快乐:)