//***********swift--1.3--可选类型--***************************

// (Optionals)即在某个数据类型后面加上问号(?)或感叹号(!)
// Int和String类型不能接受nil的,但程序运行过程中有时被复制给nil是在所难免的,Swift为每一种数据类型提供一种可选类型(optional),即在某个数据类型后面加上问号(?)或感叹号(!)
var nn1: Int? = 10; nn1 = nil
let str22: String! = nil

// Swift 的可选(Optional)类型,用于处理值缺失的情况。可选表示"那儿有一个值,并且它等于 x "或者"那儿没有值"。

// 可选类型值拆包:在可选类型的问号(?)或叹号(!)究竟有什么区别呢?这与可选类型的“拆包”(unwrapping)有关,拆包是将可选类型变成普通类型,如果我们直接打印非空的可选类型值,代码如下:

var n1: Int? = 10
print(n1)
// print(n1 + 100)
// 输出的结果是Optional(10),而非10。所以试图计算表达式n1 + 100会发生编译错误,代码如下:

var n2: Int? = 10
// print(n2 + 100) //发生编译错误

// 需要对可选类型值进行“拆包”是必要地。
// “拆包”分为显示拆包和隐性拆包。

// 使用问号(?)声明的可选类型,在拆包时需要使用叹号(!),这种拆包方式称为“显式拆包”;
// 使用叹号(!)声明的可选类型,在拆包时可以不使用叹号(!),这种表示方式称为“隐式拆包”。


// Swfit语言定义后缀?作为命名类型Optional的简写,换句话说,以下两种声明是相等的:
var optionalInteger: Int?
var optionalInteger1:Optional<Int>

// 在这两种情况下,变量optionalInteger都是可选整数类型。注意,在类型和?之间没有空格。
// Optional 是一个含有两种情况的枚举,None和Some(T),用来表示可能有或可能没有值。任何类型都可以明确声明为(或者隐式转换)可选类型。
// 当声明一个可选类型的时候,要确保用括号给?操作符一个合适的范围。例如,声明可选整数数组,应该写成(Int[])?;写成Int[]?会报错

// 当你声明一个可选变量或者可选属性的时候没有提供初始值,它的值会默认为nil。

// 可选项遵照LogicValue协议,因此可以出现在布尔环境中。在这种情况下,如果可选类型T?包含类型为T的任何值(也就是说它的值是Optional.Some(T)),这个可选类型等于true,反之为false。
// 如果一个可选类型的实例包含一个值,你可以用后缀操作符 !来访问这个值,如下所示:

optionalInteger = 43
optionalInteger! // 43

// 使用操作符!去获取值为nil的可选变量会有运行时错误。
// 我们可以用可选链接和可选绑定选择性执行可选表达式上的操作。如果值为nil,任何操作都不会执行,也不会有运行报错。
var optiongString:String? = nil

if (optiongString != nil) {
    print(optiongString)
} else  {
    print("字符串为 nil")
}
// 可选类型类似于Objective-C中指针的nil值,但是nil只对类(class)有用,而可选类型对所有的类型都可用,并且更安全。

//***********swift--1.3.1--强制解包--***************************

// 当你确定可选类型确实包含值之后,你可以在可选变量+!来获取值。这个!表示"我知道这个可选变量有值,请使用它",这被称为可选值的强制解析(forced unwrapping)。
// 注意:使用!来获取一个不存在的可选值会导致运行时错误。使用!来强制解析值之前,一定要确定可选包含一个非nil的值。

var unwarppingString:String?
unwarppingString = "unwarppingString!"

print(unwarppingString!)


//***********swift--1.3.2--自定解包--***************************
// 你可以在声明可选变量时使用感叹号(!)替换问号(?)。这样可选变量在使用时就不需要再加一个感叹号(!)来获取值,它会自动解析。

var autoWarppingString:String!
autoWarppingString = "autoWarppingString!"

print(autoWarppingString)


//***********swift--1.3.3--可选绑定--***************************
// 使用可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在if和while语句中来对可选类型的值进行判断并把值赋给一个常量或者变量。

var optionBindString:String?

//optionBindString = "optionBindString!"

if let yourBindString = optionBindString {
    print("你的字符串值为 - \(yourBindString)")
}else{
    print("你的字符串没有值")
}



// 思考:  swift  optiongal 有什么用?
// 1.Bool? 类型可以又三种值, true | false | nil, 可以表示三种状态。比如在网络返回时用 nil 表示网络请求失败,true 表示成功, false 表示 server 收到数据,但是处理结果是错误。通过一种类型,把三种情况区别出来,增加了语言的抽象能力。

var result: Bool?
// 如果你真的想要 false 等同于 nil 的效果,我觉得那种情况里,多半应该这么写:
//if result == true {
//    
//}
result = true
if result != nil {
    if  result==true {
        print("result == true")
    } else {
        print("result == false")
    }
} else {
     print("result == nil")
}


// 2.函数/字典的参数值 value 可以为nil (与oc不同)

func testObject(object:AnyObject?, forKey:String?) {
}
testObject(object: optionBindString as AnyObject?, forKey: "test");

let tsetDict :Dictionary<String,AnyObject?>= ["key1":"value1" as AnyObject?,"key2":optionBindString as AnyObject?]

print("******tsetDict********\(tsetDict)")

// 3.一定要使用正常的可选类型。
// 注:如果一个可选类型存在没有值的可能的话,不应该使用解包(隐式)可选类型。这种情况下,一定要使用正常的可选类型。
// 这句话我个人是这样理解的,如var view:UIView。当我的整个应用中或整个类中不可能存在view = nil的情况时可以设置为var view:UIView! 否则就可声明为var view:UIView?

/*

 之前一直对option的概念很感兴趣,苹果公司用option来包括一切,任何语言都会因为数据的匹配读取为空或者不匹配而产生一系列的问题,很显然,苹果公司有想利用option来弥补这种漏洞的野心。

 option真正是什么,如果他包裹了一个数据,那么他如果其实真正是什么他就不会去关心,而是很完整的告诉下一个执行,哦,我给你的是一个option的类型,具体的话,你自己想要知道,就自己去看。

 网上已经有很多option的讲解,option其实是一个结构体,一个有nil,set组成的结构体,如果没有值的时候,就会给nil,如果有值,就会把值附载在set上,传给需要调用的数据。

 解包 (!) 是一个很有意思的想法,如果有了option来包裹,做真正安全的数据类型,为什么还要解包,因为要用里面的值,但是注意必须要有值可用才可以

 很简单的来说,swift创造了一种不会出错的安全数据类型来承接很多我们未知的数据,这样可以避免一些数据问题。也统一处理了数据上的差异。 

 */