作者:fengsh998
原文地址:http://blog.csdn.net/fengsh998/article/details/28904115
转载请注明出处
假设认为文章对你有所帮助。请通过留言或关注微信公众帐号fengsh998来支持我,谢谢。


可选类型、隐式可选类型

在swift中。可选类型其根源是一个枚举型。里面有None和Some两种类型。事实上所谓的nil就是Optional.None, 非nil就是Optional.Some, 然后会通过Some(T)包装(wrap)原始值,这也是为什么在使用Optional的时候要拆包(从enum里取出来原始值)的原因, 也是PlayGround会把Optional值显示为相似{Some "hello world"}的原因。这里是enum Optional的定义:

enum Optional<T> : LogicValue, Reflectable {
case None
case Some(T)
init()
init(_ some: T) /// Allow use in a Boolean context.
func getLogicValue() -> Bool /// Haskell's fmap, which was mis-named
func map<U>(f: (T) -> U) -> U? func getMirror() -> Mirror
}

语法使用“?”操作符及"!"号操作符

如:“var optionalString: String? = "Hello"
optionalString == nil
 
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}”

大家把optionalName改为nil时看一下会有什么结果?依照理解,应该是? = 后的为可选值。即当我们的的变量为nil时。这里假设有?=操作,则会使用?=后的值作为默认值,而不会为nil. 这个等有环境时,验证一下。

经验证:

分别执行:

        var optional :String?

= "ok good";//注意?与=号之间有空格?号紧贴最后一个字母不能有空格
println(optional)

输出为:

ok good

        var optional :String?//注意?与=号之间有空格?

号紧贴最后一个字母不能有空格
println(optional)

输出为:

nil

来看下。号,官方释为隐式解包:主要用在一个变量/常量在定义瞬间完毕之后值一定会存在的情况。

这主要用在类的初始化过程中。

官风样例:

let possibleString: String? = "An optional string."
println(possibleString!) // requires an exclamation mark to access its value
// prints "An optional string." let assumedString: String! = "An implicitly unwrapped optional string."
println(assumedString) // no exclamation mark is needed to access its value

实说话,你照这个样例执行,还真看不出什么,得不出什么结论。因此我自己Z磨着,试着理解一个英文翻译。再自己操刀练习。

得出以下的一些结论。

        var optionVariables:String? //?相当于以下这样的写法的语法糖
//var optionVariables : Optional<Int>
let value = optionVariables?.hashValue
/*
optionVariables是可选类型的字符串。假设optionVariables是nil。则hashValue也为nil
假设optionVariables不为nil,hashValue就是strValue字符串的哈希值
到这里我们看到了? 的两种使用场景:
1.声明Optional值变量
2.用在对Optional值操作中,用来推断能否响应后面的操作
*/ //对于可选类型变量,不能直接进行操作。否则会报错
//let hashval = optionVariables.hashValue //'String? ' does not have a member named 'hashValue'
//因此要訪问值就须要解包,解包有两种
//第一种:使用if let/var xxx =
if let hv = optionVariables
{
//run ok;
} //另外一种:使用!号
let hv = optionVariables!.hashValue //这里的!表示“我确定这里的的strValue一定是非nil的,尽情调用吧” 。比方这样的情况: if optionVariables {
let hashv = optionVariables!.hashValue
}
//{}里的optionVariables一定是非nil的,所以就能直接加上!,强制拆包(unwrap)并执行后面的操作

凡在变量或常量后加上?

的都是一个可选变量/可选常量
凡在变量或常量后加上!的都是隐式可选变量/常量,有点难理解,首先该变量或常量满足可选类型。其主要是可被当生一般的变量/常量来使用,而不须要每次都验证是否有值。

注:假设一个隐式解包的可选类型不包括一个实际值,那么对它的訪问会抛出一个执行时错误。在变量/常量名后面加!

的情况也是一样的。

        var possibleString: String?

= "An optional string."
//possibleString = nil
println(possibleString) // possibleString 为可选变量。须要使用!来訪问的值

分析:首先 possibleString 因后面带上了?说明这是一个可选的。同一时候前面加上var为变量,所以这是一个可选类型的变量。其可选值为 "An optional string." 再来看执行println后,能够看出输出为 An optional string. 这点非常明显。再来看一下把println这句改一下改为 (即在可选变量后面加上一个!号。)

<span style="font-size:18px;">println(possibleString!) // possibleString 为可选变量,须要使用!来訪问的值</span>

这里结果与没有加!号时是全然一样的。输出为An optional string. 

好,如今重点来了,这是非常关键的一个測试。把possibleString = nil 这句凝视放开让其动行,再分别来看一下println带!和不带!的情况:

情况一:不带!号时。输出为nil .

<span style="font-size:18px;">        var possibleString: String?

= "An optional string."
possibleString = nil
println(possibleString) </span>

情况二:再来看一下带!号

<span style="font-size:18px;">        var possibleString: String? = "An optional string."
possibleString = nil
println(possibleString!) // possibleString 为可选变量。须要使用!来訪问的值</span>

这时执行到这句println就会crash了。

会报

fatal error: Can't unwrap Optional.None

错误。 

在情况一时。为什么不会报错,是由于这是一个可选变量当变量为nil时,自己主动验证是否有可选的值,有则使用可选值,在情况二,加上!訪问符来訪问possibleString 变量。但由于possibleString设为了nil (等价于var possibleString: String?) 其并没有包括一个实际值,所以抛异常.相同对于以下使用!号来声明的也一样道:

<span style="font-size:18px;">        var assumedString: String! = "An implicitly unwrapped optional string."
assumedString = nil
println(assumedString!)</span>

相同会报:fatal error: Can't unwrap Optional.None

假设你定义了一个可选类型而且没有给予初始值的时候,会默认设置为nil
var surveyAnswer: String?

// 初自己主动设置为nil
注: Swift 的nil不同于Object-C中的nil. Object-C中,nil是一个指针指向不存在的对象。

Swift中。nil不是指针而是一个特定类型的空值。不论什么类型的可选变量都能够被设为nil,不光是指针。

在swift中作何变量/常量的声明都必须带有初始值,否则就要声明为可选型。

即var btn:UIButton 这样是编译报错的。因些必须改为带初始化的如:

var btn2 :UIButton = UIButton()

或者使用? 和! 来约束。

因此经常声明可选或隐式可选变量如:

var btn :UIButton?      // 默认btn = nil

var edt :UITextField!  // 默认edt = nil

至于什么时候使用?

什么情况下使用!号来约束变量,我还没有悟出真真原理。

因此借助于自己的几次验证来帮助大家理解。

<span style="font-size:18px;">        var btn  :UIButton?      // 默认btn = nil
var btn2 :UIButton = UIButton() // 默认实例化一个对对象
var btn3 :UIButton! // 默认btn = nil
//var btn4 :UIButton //编译期报错 要求进行初始化操作
//执行会报错fatal error: Can't unwrap Optional.None 因btn = nil
btn!.tintColor = UIColor.blackColor()
btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
btn!.frame = CGRectMake(0,0,50,40) //执行正常
btn2.tintColor = UIColor.blackColor()
btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
btn2.frame = CGRectMake(0,0,50,40) //执行会报错fatal error: Can't unwrap Optional.None 因btn3 = nil
btn3.tintColor = UIColor.blackColor()
btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
btn3.frame = CGRectMake(0,0,50,40)</span>

因此为了执行期不crash能够改为例如以下:

<span style="font-size:18px;">        var btn  :UIButton?

// 默认btn = nil
var btn2 :UIButton = UIButton() // 默认实例化一个对对象
var btn3 :UIButton! // 默认btn = nil //执行会报错fatal error: Can't unwrap Optional.None 因btn = nil
if var tmpbtn = btn
{
btn!.tintColor = UIColor.blackColor()
btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
btn!.frame = CGRectMake(0,0,50,40)
} //执行正常
btn2.tintColor = UIColor.blackColor()
btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
btn2.frame = CGRectMake(0,0,50,40) //执行会报错fatal error: Can't unwrap Optional.None 因btn3 = nil
if var tmpbtn = btn
{
btn3.tintColor = UIColor.blackColor()
btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
btn3.frame = CGRectMake(0,0,50,40)
}</span>

或者

<span style="font-size:18px;">        var btn  :UIButton?      // 默认btn = nil
var btn2 :UIButton = UIButton() // 默认实例化一个对对象
var btn3 :UIButton! // 默认btn = nil //执行会报错fatal error: Can't unwrap Optional.None 因btn = nil
if btn
{
btn!.tintColor = UIColor.blackColor()
btn!.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
btn!.frame = CGRectMake(0,0,50,40)
} //执行正常
btn2.tintColor = UIColor.blackColor()
btn2.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
btn2.frame = CGRectMake(0,0,50,40) //执行会报错fatal error: Can't unwrap Optional.None 因btn3 = nil
if btn3
{
btn3.tintColor = UIColor.blackColor()
btn3.imageEdgeInsets = UIEdgeInsets(top:1,left:2,bottom:3,right:4)
btn3.frame = CGRectMake(0,0,50,40)
}</span>

注:假设一个可选类型存在没有值的可能的话。不应该使用解包(隐式)可选类型。这样的情况下,一定要使用正常的可选类型。

这句话我个人是这样理解的,如var view:UIView。当我的整个应用中或整个类中不可能存在view = nil的情况时能够设置为var view:UIView! 否则就可声明至var view:UIView?

版权声明:本文博主原创文章,博客,未经同意不得转载。

初步swift语言学习笔记2(可选类型?和隐式可选类型!)的更多相关文章

  1. 初步swift语言学习笔记6(ARC-自己主动引用计数,内存管理)

    笔者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/31824179 转载请注明出处 假设认为文章对你有所帮助.请通过留言 ...

  2. 初步swift语言学习笔记9(OC与Swift杂)

    笔者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/34440159 转载请注明出处 假设认为文章对你有所帮助,请通过留言 ...

  3. 初步swift语言学习笔记8(保留了很多OC实现)

    笔者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/32715833 转载请注明出处 假设认为文章对你有所帮助,请通过留言 ...

  4. SQL反模式学习笔记19 使用*号,隐式的列

    目标:减少输入 反模式:捷径会让你迷失方向 使用通配符和未命名的列能够达到减少输入的目的,但是这个习惯会带来一些危害. 1.破坏代码重构:增加一列后,使用隐式的Insert插入语句报错: 2.查询中使 ...

  5. Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL

    Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL 1.1. $ 美元字符, php 黑头1 1.2. 默认变量的范围和声明:1 1.3 ...

  6. 【Swift】从零开始的Swift语言学习笔记-1:前言&Hello World

    该系列分为两个大的部分. Swift基本语法 使用Xcode编写iOS应用程式 两个部分会双线并行更新. 本人的学习资料大多为Apple Develop官方上的生肉,难免会有疏漏,望斧正. 另外该系列 ...

  7. JavaScript学习笔记——数据类型强制转换和隐式转换

    javascript数据类型强制转换 一.转换为数值类型 Number(参数) 把任何的类型转换为数值类型 A.如果是布尔值,false为0,true为1 B.如果是数字,转换成为本身.将无意义的后导 ...

  8. Android学习笔记_17_Intent匹配规则(隐式意图)

    Android基本的设计理念是鼓励减少组件间的耦合,因此Android提供了Intent (意图) ,Intent提供了一种通用的消息系统,它允许在你的应用程序与其它的应用程序间传递Intent来执行 ...

  9. 【SWIFT】从零开始的SWIFT语言学习笔记-2:简单值、数组与字典

    1.0.3 简单值.数组与字典 知识点: 使用var创建变量 var myVariable = 65 myVariable = myVariable + 1 使用let创建常量 let myConst ...

随机推荐

  1. visual studio 2013 使用IIS Express附加调试MVC5

    1.如何找到调试的站点的进程[由于图片无法上传,就不上传图片了] 2.vs运行的时候,在状态栏会存在一个IIS Express 进程,点击显示所有的应用程序,找到想要调试的程序的PID; 3.附加调试 ...

  2. sort函数简单调用方法

    向量调用sort函数排序,一般有三个参数,即为sort(v.begin(),v.end(),cmp),第三个传入的是比较函数的地址(函数名),决定你比较的性质,运用灵活 #include<ios ...

  3. 解决mac 10.11 以后 无法使用未签名第三驱动

    解决 最新版 mac 系统 无法使用未签名第三驱动 10.12.多 我的情况是 10.11.4 Beta (15E27e) 使用绿联usb网卡不正常. 下面的命令为检测驱动是否装载的一些命令.sudo ...

  4. Hadoop学习笔记(2)hadoop框架解析

    Hadoop是适合大数据的分布式存储与计算平台 HDFS的架构:主从式结构 主节点只有一个NameNode,从节点可以有很多个DataNode. NameNode负责: (1)接收用户操作请求 (2) ...

  5. servlet操作数据库

    工具:myeclipse 数据库工具:mysql java ee操作数据库,首先要导入数据库驱动文件,我用的是mysql 刚开始,很多人代码正确但是就是连接不上,原因就是忘了驱动文件的导入. 我的驱动 ...

  6. jquery初学笔记

    官方网站:http://jquery.com/ 一个简单的JQuery实例: <!DOCTYPE html> <html lang="en" xmlns=&quo ...

  7. Oracle的大数据类型,BIG DATA TYPE

    1.CLOB 字符LOB类型,主要用于存储大型英文字符 2.NCLOB 国际语言字符LOB类型,主要用于存储大型非英文字符 3.BLOB 二进制LOB类型,主要用于存储二进制数据 4.BFILE 二进 ...

  8. IOS 表视图(UITableVIew)的使用方法(4)自定义表视图单元

    UITableViewCell的自定义往往需要自建一个UITableViewCell的子类后进行作业.开发者可以选择通过xib或者直接在UITableViewCell的布局中进行UITableView ...

  9. Delphi 的动态数组

    传统的Pascal 语言其数组大小是预先确定的,当你用数组结构声明数据类型时,你必须指定数组元素的个数.专业程序员也许知道些许动态数组的实现技术,一般是采用指针,用手工分配并释放所需的内存. Delp ...

  10. spring与redis集成之aop整合方案

    java使用redis缓存可以使用jedis框架,jedis操作简单,没有什么复杂的东西需要学习,网上资料很多,随便看看就会了. 将spring与redis缓存集成,其实也是使用jedis框架,只不过 ...