在Swift中给出以下内容:
var optionalString: String?
let dict = NSDictionary()
以下两个陈述之间的实际区别是什么:
optionalString = dict.objectForKey("SomeKey") as? String
VS
optionalString = dict.objectForKey("SomeKey") as! String?
答案 0 :(得分:131)
实际差异在于:
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)
}
答案 1 :(得分: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
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
答案 2 :(得分:11)
as? Types
- 表示向下投射过程是可选的。该过程可以成功与否(如果向下转换失败,系统将返回nil。)如果向下转换失败,任何方式都不会崩溃。
as! Type?
- 这里的强制转换过程应该是成功的(!
表示)。结束问号表示最终结果是否为零。
有关“!”的更多信息和“?”
让我们看两个案例
考虑:
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.
这里我们告诉编译器,下击应该是成功的。如果失败,系统将崩溃。因此,当我们确定该值为非零时,我们会给!
。
答案 3 :(得分:8)
它们是Swift中两种不同形式的向下转换。
(as?
),已知为条件表单,会返回您尝试向下转换的类型的可选值。
当您不确定向下转播是否成功时,您可以使用它。 这种形式的运算符将始终返回一个可选值,并且 如果无法做出贬低,价值将为零。这使得 你要检查一个成功的沮丧。
(as!
),知道为强制表单,尝试向下转换并强制展开结果作为单个复合操作。< / p>
当您确定向下转动时,您应该使用仅 永远成功。这种形式的运算符将触发运行时 错误如果您尝试向下转换为不正确的类类型。
有关详细信息,请查看Apple文档的 Type Casting 部分。
答案 4 :(得分:6)
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
在数据类型之后立即添加?,告诉编译器变量可能包含数字。整齐!请注意,定义可选常量并不合理 - 您只能将其值设置一次,因此您可以说明它们的值是否为零。
假设我们有基于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
答案 5 :(得分:3)
也许这个代码示例可以帮助某些人理解这个原则:
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
答案 6 :(得分:0)
The first is a "conditional cast" (look under "type-casting operators" in the documentation I've linked)。如果转换成功,表达式的值将包装在一个可选项中并返回,否则返回的值为nil。
第二个意味着optionalString可以是一个字符串对象,也可能是nil。
答案 7 :(得分:0)
在Swift中记住这些运算符的模式可能最容易:The publisher of this Application could not be verified
暗示“这可能陷阱”,而!
表示“这可能是零。”
答案 8 :(得分:-1)
我是Swift的新手,写这个例子试图解释,因为我理解'选项'。如果我错了,请纠正我。
感谢。
bool
(1):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)
VS
(2):obj.lastName = obj.lName as! String
答案:(1)程序员确信obj.lastName = obj.lName as? String
包含字符串类型对象。所以只需将该值赋予“obj.lName”
。
现在,如果程序员是正确的意味着“obj.lastName”
是字符串类型对象,那么没问题。 “obj.lastName”将设置为相同的值。
但是如果程序员错误意味着"obj.lName"
不是字符串类型对象,即它包含一些其他类型的对象,如“NSNumber”等。然后CRASH(运行时错误)。
(2)程序员不确定"obj.lName"
是否包含字符串类型对象或任何其他类型对象。因此,如果它是字符串类型,请将该值设置为“obj.lName”
。
现在,如果程序员是正确的意味着“obj.lastName”
是字符串类型对象,那么没问题。 “obj.lName”
将设置为相同的值。
但是如果程序员错误意味着obj.lName不是字符串类型对象,即它包含一些其他类型的对象,如“obj.lastName”
等。然后"NSNumber"
将设置为nil值。所以,没有崩溃(快乐:)