Swift中的低价选项:as?输入,或者!类型?

sdd*_*sma 91 downcast optional optional-variables swift

在Swift中给出以下内容:

var optionalString: String?
let dict = NSDictionary()
Run Code Online (Sandbox Code Playgroud)

以下两个陈述之间的实际区别是什么:

optionalString = dict.objectForKey("SomeKey") as? String
Run Code Online (Sandbox Code Playgroud)

VS

optionalString = dict.objectForKey("SomeKey") as! String?
Run Code Online (Sandbox Code Playgroud)

vac*_*ama 135

实际的区别在于:

var optionalString = dict["SomeKey"] as? String
Run Code Online (Sandbox Code Playgroud)

optionalString将是一个类型的变量String?.如果底层类型不是a,那么String将无害地分配nil给可选项.

var optionalString = dict["SomeKey"] as! String?
Run Code Online (Sandbox Code Playgroud)

这说,我知道这件事是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)
}
Run Code Online (Sandbox Code Playgroud)

  • 是的@Sikander,第一个总是更好.我永远不会使用第二个. (5认同)

jis*_*ala 12

as? Types - 表示向下铸造过程是可选的.该过程可以成功与否(如果向下转换失败,系统将返回nil.)如果向下转换失败,任何方式都不会崩溃.

as! Type?- 这里下击的过程应该是成功的(!表明).结束问号表示最终结果是否为零.

有关"!"的更多信息 和"?"

我们来看两个案例

  1. 考虑:

    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
    
    Run Code Online (Sandbox Code Playgroud)

    这里我们不知道将标识符为"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
    }
    
    Run Code Online (Sandbox Code Playgroud)

    所以让我们这样记住它 - 如果?这意味着我们不确定价值是否为零(当我们不知道事情时会出现问号).

  2. 对比:

    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell. 
    
    Run Code Online (Sandbox Code Playgroud)

    在这里,我们告诉编译器,向下转换应该是成功的.如果失败,系统将崩溃.所以!当我们确定价值是非零的时候我们给出.


Sen*_*ful 11

为了澄清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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)


Sco*_*Zhu 8

它们是斯威夫特中两种不同形式的向下倾斜.

(as?),它被称为条件形式,返回您尝试向下转换的类型的可选值.

当您不确定向下转换是否成功时,您可以使用它.这种形式的运算符将始终返回一个可选值,如果无法进行向下转换,则该值将为nil.这使您可以检查成功的向下转发.


(as!),被称为强制形式,尝试向下倾斜并强制 - 将结果作为单个复合动作展开.

只有在确定向下转换将始终成功时,才应使用它.如果您尝试向下转换为不正确的类类型,则此形式的运算符将触发运行时错误.

有关更多详细信息,请查看Apple文档的Type Casting部分.


swi*_*Boy 7

  • as 用于向上倾斜和类型铸造到桥接类型
  • as? 用于安全铸造,如果失败则返回零
  • 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?)
Run Code Online (Sandbox Code Playgroud)

var age: Int? = nil
var height: Int? = 180
Run Code Online (Sandbox Code Playgroud)

通过添加在数据类型之后,您告诉编译器该变量可能包含数字.整齐!请注意,定义可选常量并没有多大意义 - 您只能将其值设置一次,因此您可以说明它们的值是否为零.

什么时候应该使用"?" 什么时候 "!"

假设我们有基于UIKit的简单应用程序.我们在视图控制器中有一些代码,并希望在它上面呈现一个新的视图控制器.我们需要决定使用导航控制器在屏幕上推送新视图.

我们知道每个ViewController实例都有一个属性导航控制器.如果要构建基于导航控制器的应用程序,则应用程序主视图控制器的此属性会自动设置,您可以使用它来推送或弹出视图控制器.如果您使用单个应用程序项目模板 - 将不会自动为您创建导航控制器,因此您的应用程序的默认视图控制器将不会在navigationController属性中存储任何内容.

我敢肯定你已经猜到这是一个Optional数据类型的情况.如果检查UIViewController,您将看到该属性定义为:

var navigationController: UINavigationController? { get }
Run Code Online (Sandbox Code Playgroud)

那么让我们回到我们的用例.如果您知道您的视图控制器将始终具有导航控制器,您可以继续并强行打开它:

controller.navigationController!.pushViewController(myViewController, animated: true)
Run Code Online (Sandbox Code Playgroud)

当你放一个!你告诉编译器的属性名称后面的我不关心这个属性是可选的,我知道,当这个代码执行时时会出现一个保值所以对待这个可选像一个正常的数据类型.那不是很好吗?如果您的视图控制器没有导航控制器会发生什么?如果你的建议总是会有一个存储在navigationController中的值是错误的?你的应用会崩溃.简单而丑陋.

所以,使用!只有当你有101%确定这是安全的时候.

如果你不确定总会有导航控制器怎么样?那你可以用吗?代替 !:

controller.navigationController?.pushViewController(myViewController, animated: true)
Run Code Online (Sandbox Code Playgroud)

什么?后面的属性名告诉编译器是我不知道该物业是否包含零或一个值,所以如果它的价值使用它,oterwise只考虑整个表达式零.有效的?允许您在有导航控制器的情况下使用该属性.如果检查任何种类或任何类型的铸件,请勿.当您不关心是否有导航控制器时,这种语法是完美的,并且只有在有的情况下才想做某事.

非常感谢Fantageek