好多小伙伴都建议我学Swift,学我肯定是要学的,毕竟Swift是明日之星啊,本来想着学完OC再来的,然而现在学到UI也没有太大阻力,而且我学OC的时候也经常类比Java,理解的也比较快,所以感觉再同时学Swift也不是不可以啊~于是乎,闲暇时间开始看Swift基础。
一基本数据类型
// var 变量, let 常量
var myVariable = 123
let huihui = 23
myVariable = 21
// Swift支持类型推导(Type Inference),所以上面的代码不需指定类型,如果需要指定类型,如下
let dou:Double = 66
//注:实际编程中很少需要使用类型注解,定义常量或者变量的时候Swift已经根据初始化的值确定了类型信息。Swift几乎都可以隐式的确定变量或常量的类型,
//Swift中可以使用几乎任何字符来作为常量和变量名,包括Unicode,比如:
//但是名称中不能含有数学符号,箭头,无效的Unicode,横线-和制表符,且不能以数字开头,尽管数字可以包含在名称里。一旦完成了声明,就不能再次声明相同名称的变量或常量,或者改变它的类型。变量和常量也不能互换
let 大圣 = "孙悟空"
print(大圣)//控制台打印出孙悟空
现在Swift中print取代了println,效果一样,打出一行后面自动换行
//整数和浮点数转换
//整数和浮点类型之间的转化必须显式声明:
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi equals 3.14159, and is inferred to beof typde Double
//这里,常量three的值被用来创建Double类型的新变量,从而使表达式两侧是相同的类型。如果没有这个转换,加法操作不会被允许。反之亦然,一个整数类型可以用double或float值进行初始化:
let integerPi = Int(pi)
// integerPi equals 3, and is inferred tobe of type Int
//当使用这种方式初始化一个新的整数值的时候,浮点值总是被截断。这意味着,4.75变为4,和-3.9变为-3
//数值量表达
let decimalInteger = 17
let binaryInteger = 0b10001 // 17 in binary notation
let octalInteger = 0o21 // 17 in octal notation
let hexadecimalInteger = 0x11 // 17 inhexadecimal notation
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0
let justOverOneMillion = 1_000_000.000_000_1
//类型别名
//类型别名为现有类型定义的可替代名称。你可以使用typealias关键字定义类型别名。类型别名可以帮助你使用更符合上下文语境的名字来指代一个已存在的类型,比如处理一个外来的有指定长度的类型的时候:
typealias AudioSample = UInt16//无符号16位整数
//一旦你定义了一个类型别名,你可以在任何可能使用原来的名称地方使用别名:
var maxAmplitudeFound = AudioSample.max
// maxAmplitudeFound is now 65535
//这里,AudioSample被定义为一个UInt16的别名。因为它是一个别名,调用AudioSample.min实际上是调用UInt16.min,从而给maxAmplitudeFound变量赋初始值0。
//布尔类型
//Swift中的布尔类型使用Bool定义,也被称为Logical(逻辑)类型,可选值是true和false:
let orangesAreOrange = true
let turnipsAreDelicious = false
//这里 orangesAreOrange和turnipsAreDelicious的类型被推导为Bool 因为他们被初始化被Bool类型的常值。跟Int和Double类型一样,在定义布尔类型的时候不需要显式的给出数据类型,只需要直接赋值为true或false即可 。当使用确定类型的常值初始化一个常量/变量的时候,类型推导使Swift代码更精确和可读。 布尔类型在条件语句中特别适用,比如在if语句中
if turnipsAreDelicious {
print("Mmm, tasty turnips!")
} else {
print("Eww, turnips are horrible.")
}
//像if语句这样的条件语句,我们会在之后的章节ControlFlow有详细介绍。 Swift的类型安全策略会防止其他非布尔类型转换为布尔类型使用,比
//let i = 1
//if i {
// this example will not compile, and will report an error
//}
//就会报错,但这在其他编程语言中是可行的。但是如下的定义是正确的:
let i = 1
if i == 1 {
// this example will compile successfully
}
//i == 1的结果就是一个布尔类型,所以可以通过类型检查。像i==1这种比较将会在章节[Basic Operators]中讨论。上面的例子也是一个Swift类型安全的例子。类型安全避免了偶然的类型错误,保证了代码的意图是明确的。
//Swift不支持隐式类型转换(Implicitly casting),所以下面的代码需要显式类型转换(Explicitly casting):
let label = "The width is "
let width = 94
var v = label + String(width)
//元组类型
//元组类型可以将一些不同的数据类型组装成一个元素,这些数据类型可以是任意类型,并且不需要是同样的类型。
//在下面的例子中,(404, “Not Found”) 是一个HTTP状态码。HTTP状态码是请求网页的时候返回的一种特定的状态编码。404错误的具体含义是页面未找到。
let http404Error = (404, "Not Found") // http404Error is of type (Int, String), and equals (404, “Not Found”)
//这个元组由一个Int和一个字符串String组成,这样的组合即包含了数字,也包含了便于人们认知的字符串描述。这个元组可以描述为类型(Int,String)的元组。
//编程人员可以随意地创建自己需要的元组类型,比如 (Int, Int, Int), 或者(String, Bool)等。同时组成元组的类型数量也是不限的。 可以通过如下方式分别访问一个元组的值:
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// prints "The status code is 404"
print("The status message is \(statusMessage)")
// prints "The status message is Not Found"
//如果仅需要元组中的个别值,可以使用(_)来忽略不需要的值
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// prints "The status code is 404"
//另外,也可以使用元素序号来选择元组中的值,注意序号是从0开始的
print("The status code is \(http404Error.0)")
// prints "The status code is 404"
print("The status message is \(http404Error.1)")
// prints "The status message is Not Found"
//在创建一个元组的时候,也可以直接指定每个元素的名称,然后直接使用元组名.元素名访问,如:
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
// prints "The status code is 200"
print("The status message is \(http200Status.description)")
// prints "The status message is OK"
//元组类型在作为函数返回值的时候特别适用,可以为函数返回更多的用户需要的信息。比如一个请求web页面的函数可以返回(Int,String)类型的元组来表征页面获取的成功或者失败。返回两个不同类型组成的元组可以比只返回一个类型的一个值提供更多的返回信息。
//可选类型
//在一个值可能不存在的时候,可以使用可选类型。这种类型的定义是:要么存在这个值,且等于x,要么在这个值 不存在。
//下面给出一个例子,在Swift中有一个叫Int()的方法,能够将一个里面的参数转为一个Int类型。但是需要注意的是,不是所有的字符串都可以转换为整数。比如字符串”123″可以转换为123,但是”hello, world”就不能被转换。
var possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber is inferred to be of type "Int?", or "optional Int"
//由于Int()方法可能会失败,因此它会返回一个可选的Int类型,而不同于Int类型。一个可选的Int类型被记为Int?,不是Int。问号表明它的值是可选的,可能返回的是一个Int,或者返回的值不存在。
Int("yu3") //这样就会返回nil
//if语句和强制解包
//编程人员可以使用if语句来检测一个可选类型是否包含一个特定的值,如果一个可选类型确实包含一个值,在if语句中它将返回true,否则返回false。如果你已经检测确认该值存在,那么可以使用或者输出它,在输出的时候只需要在名称后面加上感叹号(!)即可,意思是告诉编译器:我已经检测好这个值了,可以使用它了。如:
if convertedNumber != nil {
print("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
print("\(possibleNumber) could not be converted to an integer")
}
//选择绑定
//选择绑定帮助确定一个可选值是不是包含了一个值,如果包含,把该值转化成一个临时常量或者变量。选择绑定可以用在if或while语句中,用来在可选类型外部检查是否有值并提取可能的值。
//方法如下:
//if let constantName = someOptional {
// statements
//}
//那么上一个例子也可以改写为:
possibleNumber = "huihui"
if let actualNumber = Int(possibleNumber) {
print("\(possibleNumber) has an integer value of \(actualNumber)")
} else {
print("\(possibleNumber) could not be converted to an integer")
}
//上述代码理解起来不难:如果 Int(possibleNumber) 返回的这个可选Int类型包含一个值,那么定义一个常量actualNumber来等于这个值,并在 后续代码中直接使用。
//如果转换是成功的,那么actualNumber常量在if的第一个分支可用,并且被初始化为可选类型包含的值,同时也不需要使用!前缀。这个例子里,actualNumber只是简单的被用来打印结果。
//常量和变量都可以用来做可选绑定。如果你想要在if第一个分支修改actualNumber的值,可以写成if var actualNumber, actualNumber就成为一个变量从而可以被修改。
//nil
//可以给可选类型指定一个特殊的值nil:
var serverResponseCode: Int? = 404
// serverResponseCode contains an actual Int value of 404
serverResponseCode = nil
// serverResponseCode now contains no value
//如果你定义了一个可选类型并且没有给予初始值的时候,会默认设置为nil
var kong: String?
//注: Swift 的nil不同于OC中的nil. OC中,nil是一个指针指向不存在的对象。Swift中,nil不是指针而是一个特定类型的空值。任何类型的可选变量都可以被设为nil,不光是指针。
//隐式解包可选类型
//在上面的例子中,可选类型表示一个常量/变量可以没有值。可选类型可以被if语句检测是否有值,并且可以被可选绑定解包。
//但是在一些情况下,可选类型是一直有效的,那么可以通过定义来隐式地去掉类型检查,强制使用可选类型。这些可选类型被成为隐式解包的可选类型。你可以直接在类型后面加! 而不是?来指定。
//隐式解包的可选类型主要用在一个变量/常量在定义瞬间完成之后值一定会存在的情况。
//隐式解包的可选类型本质是可选类型,但是可以被当成一般类型来使用,不需要每次验证值是否存在。如下的例子展示了可选类型和解包可选类型之间的区别。
let possibleString: String? = "An optional string."
print(possibleString!) // requires an exclamation mark to access its value
// prints "An optional string."
var assumedString: String! = "An implicitly unwrapped optional string."
assumedString = nil
//print(assumedString) 会报错
//fatal error: unexpectedly found nil while unwrapping an Optional value
//可以把隐式解包可选类型当成对每次使用的时候自动解包的可选类型。即不是每次使用的时候在变量/常量后面加!而是直接在定义的时候加。
//注:如果一个隐式解包的可选类型不包含一个实际值,那么对它的访问会抛出一个运行时错误。在变量/常量名后面加!的情况也是一样的。
//你依然可以把解包可选类型当成正常的可选类型来探测是否有值。
assumedString = "huihui"
if assumedString != nil {
print(assumedString)
}
//或者通过选择绑定检查
if let definiteString = assumedString {
print(definiteString)
}
//注:如果一个可选类型存在没有值的可能的话,不应该使用解包可选类型。这种情况下,一定要使用正常的可选类型。
//断言
//可选类型让编程人员可以在运行期检测一个值是否存在,然后使用代码来处理不存在的情况。但是有些情况下,如果一个值 不存在或者值不满足条件会直接影响代码的执行,这个时候就需要使用断言。这种情况下,断言结束程序的执行从而提供调试的依据。
//使用断言调试
//断言是一种实时检测条件是否为true的方法,也就是说,断言假定条件为true。断言保证了后续代码的执行依赖于条件的成立。如果条件满足,那么代码继续执行,如果这个条件为false,那么代码将会中断执行。
//在Xcode中,在调试的时候如果中断,可以通过查看调试语句来查看断言失败时的程序状态。断言也能提供适合的debug信息。 使用全局函数assert来使用断言调试,assert函数接受一个布尔表达式和一个断言失败时显示的消息,如:
let age = -3
//assert(age > 0, "A person‘s age cannot be less than zero")
//上面那行控制台报错:
//assertion failed: A person‘s age cannot be less than zero: file <EXPR>, line 205
//当前一个条件返回false的时候,后面的错误日志将会输出。
//在这个例子中,只有当age >= 0的时候,条件被判定为true,但是age = -3,所以条件判定为false,输出错误日志 “A person’s age cannot be less than zero”。
//当然错误日志也可以省略,但是这样不利于调试,如
assert(age >= 0)
//上面的控制台报错:
//assertion failed: : file <EXPR>, line 213
//使用断言的时机
//当需要检测一个条件可能是false,但是代码运行必须返回true的时候使用。下面给出了一些常用场景,可能会用到断言检测:
//传递一个整数类型下标的时候,比如作为数组的Index,这个值可能太小或者太大,从而造成数组越界;
//传递给函数的参数,但是一个无效的参数将不能在该函数中执行
//一个可选类型现在是nil,但是在接下来的代码中,需要是非nil的值才能够继续运行。
//注:断言会导致程序运行的中止,所以如果异常是预期可能发生的,那么断言是不合适的。这种情况下,异常是更合适的。断言保证错误在开发过程中会被发现,发布的应用里最好不要使用。
二 基本运算符
//运算符是一种特定的符号或表达式,用来检验、修改或合并变量。例如,用求和运算符+可以对两个数字进行求和(如let i = 1 + 2);稍微复杂一点的例子有逻辑与操作符&& (如if enteredDoorCode && passedRetinaScan) ,自增长运算符 ++i (这是i=i+1的简写方式)
//Swift支持C标准库中的大多数运算符并提升了各自的兼容性,从而可以排除常见的编码错误。赋值操作符 (=)不会返回一个值,这样可以防止你因粗心将赋值运算符 (=)写成 (==)而引起错误。算术符(+、 -、 *、 /、 % 等)会检查与驳回值溢出,这样可以避免值类型的数据在超过值类型所允许的存储范围时,出现意想不到的数据。你可以选择使用Swift所提供的值溢出运算符进行量化溢出的行为,详细见溢出操作符。
//与C语言不同,Swift允许你对浮点数执行取余运算。同时,Swift提供两个范围的运算符 (a..<b 和 a...b),作为表示一个数值范围的简写方式,这点C不支持。
//本章节描述了Swift常见运算符。高级运算符覆盖了Swift的高级操作符,并且对自定义操作符,对自定义类型操作符的实现进行了描述。
//术语
//操作符都是一元、二元或三元:
//一元操作符操作单个对象 (如 -a)。一元前缀操作符出现在对象前(如 !b),一元后缀操作符在对象后出现 (如 i++)。
//二元操作符操作两个对象(如 2 + 3),并且操作符位于两个元素中间。
//三元操作符对两个对象进行操作。与C一样,Swift仅支持一个三元操作符:三元条件操作符 (a ? b : c).
//操作符所影响的值被称为操作数。表达式1 + 2中,符号 + 是一个二元运算符并且两个操作数分别为 1 和 2。
//赋值运算符
//赋值运算符(a = b) 用b的值去初始化或更新a 的值
let b = 10
var a = 5
a = b
// 此刻a的值为10
//假如右边赋值的数据为多个数据的元组,它的元素可以是一次性赋给的多个常量或变量
let (x, y) = (1, 2)
x
print((x, y))
// x等于1, 并且y等于2
//与C及Objective-C不同,Swift中赋值运算符并不将自身作为一个值进行返回。所以以下的代码是不合法的:
//if x = y {
// 错误, 因为x = y并不会返回一个值
//}
//此特性帮助你避免因粗心将赋值运算符 (==)写成 (=)而引起的错误。因为 if x = y 这样写是无效的。
9 % 4
-9 % 4
9 % 2.5
var i = 0
i++
++i
i--
--i
i+=2
let three = 3
let minusThree = -three // minusThree equals -3
let plusThree = -minusThree // plusThree equals 3, or "minus minus three"
let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
//范围运算符
//封闭范围运算符
//封闭范围运算符(a…b)定义了一个范围,从a到b,并包括a和b的值。
//当要在一个范围内迭代所有可能的值的时候,范围运算符是非常有用的, 例如for-in循环
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
//1 times 5 is 5
//2 times 5 is 10
//3 times 5 is 15
//4 times 5 is 20
//5 times 5 is 25
//欲了解更多for-in循环,请参阅控制流。
//半封闭的区域运算符
//半封闭的区域运算符(a..<b)定义了从a到b的范围,但不包括b。它被认为是半封闭的,因为它包含第一个值,而不包含最终值。
//半封闭的范围使用明确,当你使用从零开始的列表,如数组,它是有用的数到(但不包括)列表的长度:
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
print("Person \(i + 1) is called \(names[i])")
}
// Person 1 is called Anna
// Person 2 is called Alex
// Person 3 is called Brian
// Person 4 is called Jack
//请注意,该数组包含四个项目,但0 . .数只数到3(数组中的最后一个项目的索引),因为它是一个半封闭的范围。