1.Swift-基础

Swift:Swift 是 建立在C和Objective-C的基础之上的一门iOS 和 OS X 应用开发的一门新语言。它采纳了安全编程模式,并加入了现代语言的特点,使编程变得更加简单和有趣了。它采用了ARC模式,使内存管理变得更加简单。Swift语言对于编程新手非常的友好,它支持playgrounds,让开发者不用运行程序就可以直接看到结果。Swift是未来苹果软件开发的一门新的语言,所以学习Swift语言是一种趋势。

Swift的基本类型包括:

Int : 整型

Double和Float:浮点类型

Bool:布尔类型

String:字符串类型

Array和Dictionary:集合类型

从这些数据类型可见,Swift的命名跟Objective-C的风格差异蛮大了,有点像C#、java等其他语言的风格了。而语法,看起来更像是js等其他脚本语言了。

就像 C 语言一样,Swift 使用变量来进行存储并通过变量名来关联值。在 Swift 中,值不可变的变量有着广泛的应用,它们就是常量,而且比 C 语言的常量更强大。在 Swift 中,如果你要处理的值不需要改变,那使用常量可以让你的代码更加安全并且更好地表达你的意图。

 

除了我们熟悉的类型,Swift 还增加了 Objective-C 中没有的类型比如元组(Tuple)。元组可以让你创建或者传递一组数据,比如作为函数的返回值时,你可以用一个元组可以返回多个值。

 

Swift 还增加了可选(Optional)类型,用于处理值缺失的情况。可选表示“那儿有一个值,并且它等于 x ”或者“那儿没有值”。可选有点像在 Objective-C 中使用nil,但是它可以用在任何类型上,不仅仅是类。可选类型比 Objective-C 中的nil指针更加安全也更具表现力,它是 Swift 许多强大特性的重要组成部分。

 

Swift 是一个类型安全的语言,可选类型就是一个很好的例子。Swift 可以让你清楚地知道值的类型。如果你的代码期望得到一个String,类型安全会阻止你不小心传入一个Int。你可以在开发阶段尽早发现并修正错误。


1.常量和变量

常量和变量把一个名字(比如maximumNumberOfLoginAttempts或者welcomeMessage)和一个指定类型的值(比如数字10或者字符串"Hello")关联起来。常量的值一旦设定就不能改变,而变量的值可以随意更改。

常量和变量必须在使用之前声明,常量用let声明,变量用var声明。

let maximumNumberOfLoginAttempts = 10

var currentLoginAttempt = 0

也可以在一行代码中声明多个变量或者常量,中间用逗号隔开:

var x = 10,y = 2

可以在声明变量或者常量的时候声明它的数据类型,在常量和变量后面加上冒号再加上数据类型:

var welcomeMessage:String = "Hi"

var red,green,blue:Double


注意:很少需要写类型标注。如果你在声明常量或者变量的时候赋了一个初始值,Swift可以根据这个初始值推断出数据类型。


常量和变量的命名可以包含Unicode字符,但是不能包含数学符号、箭头、保留的Unicaode码位、连线和制表符,也不能以数字开头。如果必须用系统保留的关键字作为变量或者常量来用,可以在前面加上`符号。


Swift中的输出函数有println()和print(),这个跟java语言类似,区别是换行和不换行。

Swift语言中可以在每行代码后面省略分号。


2.整数类型

Swift 提供了8,16,32和64位的有符号和无符号整数类型。这些整数类型和 C 语言的命名方式很像,比如8位无符号整数类型是UInt8,32位有符号整数类型是Int32。就像 Swift 的其他类型一样,整数类型采用大写命名法。可以看到不同整型的数值范围:

let minUInt8Value = UInt8.min

let maxUInt8Value = UInt8.max


let minInt32Value = Int32.min

let maxInt32Value = Int32.max


let minInt64Value = Int64.min

let maxInt64Value = Int64.max


Int

一般来说,你不需要专门指定整数的长度。Swift 提供了一个特殊的整数类型Int,长度与当前平台的原生字长相同:

 

- 在32位平台上,Int和Int32长度相同。

- 在64位平台上,Int和Int64长度相同。

 

除非你需要特定长度的整数,一般来说使用Int就够了。这可以提高代码一致性和可复用性。即使是在32位平台上,Int可以存储的整数范围也可以达到-2147483648~2147483647,大多数时候这已经足够大了。

 

UInt

Swift 也提供了一个特殊的无符号类型UInt,长度与当前平台的原生字长相同:

 

- 在32位平台上,UInt和UInt32长度相同。

- 在64位平台上,UInt和UInt64长度相同。

 

注意:尽量不要使用UInt,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用Int,即使你要存储的值已知是非负的。统一使用Int可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推测,请参考类型安全和类型推测。


3.浮点数类型

浮点类型比整数类型表示的范围更大,可以存储比Int类型更大或者更小的数字。Swift 提供了两种有符号浮点数类型:

Double

表示64位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。

Float

表示32位浮点数。精度要求不高的话可以使用此类型。

 

注意:Double精确度很高,至少有15位数字,而Float最少只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围。


4.类型安全和类型推测

Swift 是一个类型安全(type safe )的语言。类型安全的语言可以让你清楚地知道代码要处理的值的类型。如果你的代码需要一个String,你绝对不可能不小心传进去一个Int。

 

由于 Swift 是类型安全的,所以它会在编译你的代码时进行类型检查(type checks),并把不匹配的类型标记为错误。这可以让你在开发的时候尽早发现并修复错误。

 

当你要处理不同类型的值时,类型检查可以帮你避免错误。然而,这并不是说你每次声明常量和变量的时候都需要显式指定类型。如果你没有显式指定类型,Swift 会使用类型推测(type inference)来选择合适的类型。有了类型推测,编译器可以在编译代码的时候自动推测出表达式的类型。原理很简单,只要检查你赋的值即可。

 

因为有类型推测,和 C 或者 Objective-C 比起来 Swift 很少需要声明类型。常量和变量虽然需要明确类型,但是大部分工作并不需要你自己来完成。

 

当你声明常量或者变量并赋初值的时候类型推测非常有用。当你在声明常量或者变量的时候赋给它们一个字面量(literal value 或 literal)即可触发类型推测。(字面量就是会直接出现在你代码中的值,比如42和3.14159。)

let inferenceInt = 3 //推测是Int

let inferenceDouble = 3.14//推测为Double

let inferenceDoubleAnother = 4 + 3.14 //推测为Double

注意:Swift总是将浮点数推测为Double类型而不是Float类型。如果表达式中同时包含了整数和浮点数,也会被推测为Double类型。


5.数值型字面量

整数字面量可以被写作:

 

- 一个十进制数,没有前缀

- 一个二进制数,前缀是0b

- 一个八进制数,前缀是0o

- 一个十六进制数,前缀是0x

 

下面的所有整数字面量的十进制值都是17:

let decimalInteger = 17 

let binaryInteger = 0b10001       // 二进制的17 

let octalInteger = 0o21           // 八进制的17 

let hexadecimalInteger = 0x11     // 十六进制的17 

浮点字面量可以是十进制(没有前缀)或者是十六进制(前缀是0x)。小数点两边必须有至少一个十进制数字(或者是十六进制的数字)。浮点字面量还有一个可选的指数(exponent),在十进制浮点数中通过大写或者小写的e来指定,在十六进制浮点数中通过大写或者小写的p来指定。

 

如果一个十进制数的指数为exp,那这个数相当于基数和$10^{exp}$的乘积:

 

1.25e2 表示 $1.25 × 10^{2}$,等于 125.0。

1.25e-2 表示 $1.25 × 10^{-2}$,等于 0.0125。

 

如果一个十六进制数的指数为exp,那这个数相当于基数和$2^{exp}$的乘积:

 

0xFp2 表示 $15 × 2^{2}$,等于 60.0。

0xFp-2 表示 $15 × 2^{-2}$,等于 3.75。

 

下面的这些浮点字面量都等于十进制的12.1875:

let decimalDouble = 12.1875 

let exponentDouble = 1.21875e1 

let hexadecimalDouble = 0xC.3p0 

数值类字面量可以包括额外的格式来增强可读性。整数和浮点数都可以添加额外的零并且包含下划线,并不会影响字面量:

let paddedDouble = 000123.456 

let oneMillion = 1_000_000 

let justOverOneMillion = 1_000_000.000_000_1 


6.数值型类型转换

通常来讲,即使代码中的整数常量和变量已知非负,也请使用Int类型。总是使用默认的整数类型可以保证你的整数常量和变量可以直接被复用并且可以匹配整数类字面量的类型推测。 只有在必要的时候才使用其他整数类型,比如要处理外部的长度明确的数据或者为了优化性能、内存占用等等。使用显式指定长度的类型可以及时发现值溢出并且可以暗示正在处理特殊数据。

a.整数类型转换

不同整数类型的变量和常量可以存储不同范围的数字。Int8类型的常量或者变量可以存储的数字范围是-128~127,而UInt8类型的常量或者变量能存储的数字范围是0~255。如果数字超出了常量或者变量可存储的范围,编译的时候会报错:

let cannotBeNegative: UInt8 = -1 

// UInt8 类型不能存储负数,所以会报错 

let tooBig: Int8 = Int8.max + 1 

// Int8 类型不能存储超过最大值的数,所以会报错 

由于每中整数类型都可以存储不同范围的值,所以你必须根据不同情况选择性使用数值型类型转换。这种选择性使用的方式,可以预防隐式转换的错误并让你的代码中的类型转换意图变得清晰。

 

要将一种数字类型转换成另一种,你要用当前值来初始化一个期望类型的新数字,这个数字的类型就是你的目标类型。在下面的例子中,常量twoThousand是UInt16类型,然而常量one是Uint8类型。它们不能直接相加,因为它们类型不同。所以要调用UInt16(one)来创建一个新的UInt16数字并用one的值来初始化,然后使用这个新数字来计算:

let twoThousand: UInt16 = 2_000 

let one: UInt8 = 1 

let twoThousandAndOne = twoThousand + UInt16(one) 

现在两个数字的类型都是UInt16,可以进行相加。目标常量twoThousandAndOne的类型被推测为UInt16,因为它是两个UInt16值的和。

 

SomeType(ofInitialValue)是调用 Swift 构造器并传入一个初始值的默认方法。在语言内部,UInt16有一个构造器,可以接受一个UInt8类型的值,所以这个构造器可以用现有的UInt8来创建一个新的UInt16。注意,你并不能传入任意类型的值,只能传入UInt16内部有对应构造器的值。不过你可以扩展现有的类型来让它可以接收其他类型的值(包括自定义类型),请参考扩展。

b.整数类型和浮点数类型之间的转换必须显式指定类型。

let three = 3

let pointOneFourFiveNine = 0.14159

let pi = Double(three) + pointOneFourFiveNine


let integerPi = Int(pi)注意浮点数转换为整数会被截断。


7.类型别名

类型别名是用关键字typealias给现有的类取一个别名。

typealias intAliase = Int

定义了一个类型别名之后,可以在任何使用原始类名的地方使用别名。

var mimIntValue = intAliase.min

8.布尔值

Swift中的布尔值类型是Bool,可选值变成了true和false。

如果在使用布尔类型的地方使用了非布尔类型,编译器会报错:

let i = 1 

if i { 

    // 这个例子不会通过编译,会报错 

let i = 1 

if i == 1 { 

 // 这个例子会编译成功 


9.元组(tuples)

元组把多个值组合成一个复合值。元组内的值可以是任意类型。比如(404,”not found”)元组把一个Int值和一个String值组合起来表示 HTTP 状态码的两个部分:一个数字和一个人类可读的描述。这个元组可以被描述为“一个类型为(Int, String)的元组”。你可以把任意顺序的类型组合成一个元组,这个元组可以包含所有类型。

//你可以将一个元组的内容分解(decompose)成单独的常量和变量,然后你就可以正常使用它们了

let (statusCode,statusMessage) = http404Error

println(statusCode)

println(statusMessage)


//如果你只需要一部分元组值,分解的时候可以把要忽略的部分用下划线(_)标记

let (justTheStatusCode,_) = http404Error

println("The status code is \(justTheStatusCode)")



//此外,你还可以通过下标来访问元组中的单个元素,下标从零开始

println(http404Error.0)

println(http404Error.1)



//你可以在定义元组的时候给单个元素命名,你可以通过名字来获取这些元素的值

let http200Status = (statusCode:200,message:"OK",otherInfo:"")

println(http200Status.statusCode)

println(http200Status.message)

println(http200Status.otherInfo)


作为函数返回值时,元组非常有用。一个用来获取网页的函数可能会返回一个(Int, String)元组来描述是否获取成功。和只能返回一个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。

注意:元组在临时组织值的时候很有用,但是并不适合创建复杂的数据结构。如果你的数据结构并不是临时使用,请使用类或者结构体而不是元组。请参考类和结构体。


10.可选类型

可选类型用来处理值可能确实的情况。可选表示:有一个值并且是x,或者,没有什么都没有。

注意:C 和 Objective-C 中并没有可选这个概念。最接近的是 Objective-C 中的一个特性,一个方法要不返回一个对象要不返回nil,nil表示“缺少一个合法的对象”。然而,这只对对象起作用——对于结构体,基本的 C 类型或者枚举类型不起作用。对于这些类型,Objective-C 方法一般会返回一个特殊值(比如NSNotFound)来暗示值缺失。这种方法假设方法的调用者知道并记得对特殊值进行判断。然而,Swift 的可选可以让你暗示任意类型的值缺失,并不需要一个特殊值。

let possibleNumber = "123"

let convertedNumber = possibleNumber.toInt()    //vonvertedNumber被推测为Int?类型


因为toInt方法可能会失败,所以它返回一个可选的(optional)Int,而不是一个Int。一个可选的Int被写作Int?而不是Int。问号暗示包含的值是可选,也就是说可能包含Int值也可能不包含值。(不能包含其他任何值比如Bool值或者String值。只能是Int或者什么都没有。)


  1. nil

只能给可选变量赋值,表示没有值。

var serverResponseCode:Int? = 404

serverResponseCode = nil


var surveyAnswer:String?  //可选类型在声明的时候没有赋值的情况下会被自动赋值为nil

//var a = nil //会报错,不能给非可选变量赋值为nil

注意:Swift 的nil和 Objective-C 中的nil并不一样。在 Objective-C 中,nil是一个指向不存在对象的指针。在 Swift 中,nil不是指针——它是一个确定的值,用来表示值缺失。任何类型的可选都可以被设置为nil,不只是对象类型。

2.if语句与强制解析

//if语句和强制解析

if convertedNumber != nil{//这个地方注意!要与 convertedNumber有空格

    println("\(convertedNumber) has an integer value \(convertedNumber!)")

}else{

    println("\(convertedNumber) could not be converted to an integer.")

}

注意:使用!来获取一个不存在的可选值会导致运行时错误。使用!来强制解析值之前,一定要确定可选包含一个非nil的值。

3.可选绑定

使用可选绑定(optional binding)来判断可选是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在if和while语句中来对可选的值进行判断并把值赋给一个常量或者变量。if和while语句,请参考控制流。

if let actualNumber = possibleNumber.toInt(){

    println("\(possibleNumber) has an integer value \(actualNumber)")

}else{

    println("\(possibleNumber) could not be converted to an integer.")

}

如果转换成功,会将值赋给 actualNumber并执行第一个分支的语句,否则执行第二个分支的语句。

4.隐式解析可选

如上所述,可选暗示了常量或者变量可以“没有值”。可选可以通过if语句来判断是否有值,如果有值的话可以通过可选绑定来解析值。

 

有时候在程序架构中,第一次被赋值之后,可以确定一个可选总会有值。在这种情况下,每次都要判断和解析可选值是非常低效的,因为可以确定它总会有值。

 

这种类型的可选被定义为隐式解析可选(implicitly unwrapped optionals)。把想要用作可选的类型的后面的问号(String?)改成感叹号(String!)来声明一个隐式解析可选。

 

当可选被第一次赋值之后就可以确定之后一直有值的时候,隐式解析可选非常有用。隐式解析可选主要被用在 Swift 中类的构造过程中,请参考类实例之间的循环强引用。

 

一个隐式解析可选其实就是一个普通的可选,但是可以被当做非可选来使用,并不需要每次都使用解析来获取可选值。下面的例子展示了可选String和隐式解析可选String之间的区别:

let possibleString: String? = "An optional string." 

println(possibleString!) // 需要惊叹号来获取值 

// 输出 "An optional string." 

 

let assumedString: String! = "An implicitly unwrapped optional string." 

println(assumedString)  // 不需要感叹号 

// 输出 "An implicitly unwrapped optional string." 

你可以把隐式解析可选当做一个可以自动解析的可选。你要做的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾。

 

注意:如果你在隐式解析可选没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选后面加一个惊叹号一样。

 

你仍然可以把隐式解析可选当做普通可选来判断它是否包含值:

if assumedString { 

    println(assumedString) 

// 输出 "An implicitly unwrapped optional string." 

你也可以在可选绑定中使用隐式解析可选来检查并解析它的值:

if let definiteString = assumedString { 

    println(definiteString) 

// 输出 "An implicitly unwrapped optional string." 

注意:如果一个变量之后可能变成nil的话请不要使用隐式解析可选。如果你需要在变量的生命周期中判断是否是nil的话,请使用普通可选类型。


目前没感觉到这个隐式解析可选有什么值得使用的地方。。。


11.断言

可选可以让你判断值是否存在,你可以在代码中优雅地处理值缺失的情况。然而,在某些情况下,如果值缺失或者值并不满足特定的条件,你的代码可能并不需要继续执行。这时,你可以在你的代码中触发一个断言(assertion)来结束代码运行并通过调试来找到值缺失的原因。

let age = -3

assert(age>=0, "age can not be less than zero.") //age>=0不满足,断言触发

assert(age>=0, "\(age) can not be less than zero.")

assert(age>=0)  //断言信息可省略

何时使用断言

当条件可能为假时使用断言,但是最终一定要保证条件为真,这样你的代码才能继续运行。断言的适用情景:

 

- 整数的附属脚本索引被传入一个自定义附属脚本实现,但是下标索引值可能太小或者太大。

- 需要给函数传入一个值,但是非法的值可能导致函数不能正常执行。

- 一个可选值现在是nil,但是后面的代码运行需要一个非nil值。

注意:断言可能导致你的应用终止运行,所以你应当仔细设计你的代码来让非法条件不会出现。然而,在你的应用发布之前,有时候非法条件可能出现,这时使用断言可以快速发现问题。



参考:1.苹果官方的The Swift Programming Language 在iBooks中可以下载到。

   2.The Swift Programming Language--语言指南--基础部分

总结:

Swift语法跟Objective-C语法差异还是蛮大的,感觉更适合脚本语言其他脚本语言程序猿或者新程序猿上手。不过Swift跟Objective-C比较起来,语法确实简化多了:不用写分号;if后面可以不写圆括号了;字符串前面不用再写@符号了;让人眼前一亮的元组概念。。。。。。从一定程度上减少了代码量。强大的类型推断,让我们一般不用再声明变量或者常量的数据类型了。安全机制,类型检查,更是在一定程度上避免了我们写出错误的代码。奇怪的类型别名,有多少程序猿在实际开发中会使用呢,原始类名跟自己定义别名,无非一个名字而已,暂时感觉没多大意义。坑爹的nil更是跟OC里面的概念不一样,它使一个确定的值,就是什么也没用,只能给可选变量赋值,这个比较坑OC程序猿。非可选类型的变量和常量在赋初值之前不能使用。因为它不是nil,不知道是什么,即使是Int类型,它也没有默认为数字0,所以一定要赋值之后再使用。let、var、asset、print/println首字母都不用大写了,这个有点反常规。最让我眼前一亮的是Swift的元组概念,它像一个数组,但是又不是数组,内容分解的步骤看起来像字典而又不是字典,其实就是数组和字典的一种简化了的类型。




你可能感兴趣的:(Swift)