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? 。 这也会导致optionalStringtypes为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”将设置为零值。 所以,没有崩溃(快乐:)