推荐一个学习网站:https://www.cnswift.orgphp
该网站是对Swift官方文档的翻译,但不是无脑翻译,而是结合做者的开发经验,在翻译的基础上,给出一些实用的建议。
常量与变量python
在Swift中规定,定义一个标识符的时候必须明确说明该标识符是常量仍是变量:swift
使用let来定义常量,定义以后不可修改;数组
使用var来定义变量,定义以后能够修改。ruby
let a: Int = 2a = 3//会报错,由于a是常量,不能够修改 var b: Int = 6b = 8//正常运行,b是变量,能够修改
基本数据类型bash
Swift中的基本数据类型包括:整型、浮点型、Bool型数据结构
整型架构
有符号整型app
Int8:有符号8位整型函数
Int16:有符号16位整型
Int32:有符号32位整型
Int64:有符号64位整型
Int:默认,和平台相关,至关于OC中的NSInteger
无符号整型
UInt8:无符号8位整型
UInt16:无符号16位整型
UInt32:无符号32位整型
UInt64:无符号64位整型
UInt:默认,和平台相关,至关于OC中的NSUInteger
浮点型
Float:32位浮点型
Double:64位浮点型(默认)
Bool型
true:真
false:假
基本数据类型的运算与OC是同样的:
a+b//加 a-b//减 a*b//乘 a/b//除 a%b//取余
a+b//加a-b//减a*b//乘a/b//除a%b//取余可是须要注意的是,在Swift中,不一样类型的数据是不能够运算的,好比整型和浮点型就不能够一块进行运算:
若是想要运算,那么就要将其中一种类型转为另外一种类型:
var c = 1var d = 1.1Double(c)+d
Swift中的类型推导
Swift是一种强类型语言,也就是说,在Swift中,任何一个变量或者常量都必须有明确的类型。
var d: Int = 8
若是在定义一个标识符的时候有直接进行赋值,那么标识符后面 的类型能够省略:
var d = 8
由于Swift有类型推导,会自动根据后面的赋值来决定前面的标识符的数据类型。
咱们能够经过option+鼠标左键来查看变量的数据类型:
须要注意的是,若是一个变量的类型已经肯定了,那么就不能够再给变量赋其余类型的值:
这里的变量c已是整型了,那么就只能给其赋整型值,不可赋其余类型的值。
运算符
计算运算符
+、-、*、/、%
须要特别注意的是,计算运算符两边的数据类型必须为同一类型,若是类型不一样,则编译器会报错。
赋值运算符
=、+=、-=、*=、/=、%=
须要特别注意的是,赋值运算符两边的数据类型必须为同一类型,若是类型不一样,则编译器会报错。
比较运算符
、>=、<、<=、==、!=
须要特别注意的是,比较运算符两边的数据类型必须为同一类型,若是类型不一样,则编译器会报错。
区间运算符
Swift特有的。
1...8 //闭区间运算符,表示从1到8(包括1和8)的全部值的区间1... //闭区间运算符,表示从1日后无限延伸...8 //闭区间运算符,表示从8往前无限延伸1..<8 //半开区间运算符,表示从1到8(包括1,可是不包括8)的全部值的区间..<8 //半开区间运算符,表示从8往前(不包括8)无限延伸
元组
OC中没有元组类型,元组是Swift中特有的一种数据结构。
元组用于定义一组数据,组成元组的数据能够称为元素。
咱们如今使用元组来描述一我的的信息:
var one = ("Norman", "male", 30, 178.5)print(one.0)
而后摁住option键单击,发现变量one的类型以下:
这个类型是根据赋的值倒推出来的。
上面的元组one中的元素从左到右一次表示:名字、性别、年龄、身高。人们乍一看,其实仍是不知道每一个元素分别表明的意思的,因此为了便于理解,为了可以见文知意,咱们还能够这样来定义元组:
//给元组中的元素加上名称,以后能够经过元素名称来访问元素 var one = (name:"Norman", gender:"male", age:30, height:178.5) print(one.name)
摁住option键单击,发现变量one的类型以下:
元组中元素的访问
//写法一 let error = (404, "Not Found") //下标访问 print(error.0) print(error.1) //写法二 let error = (errorCode:404, errorInfo:"Not Found") //别名访问 print(error.errorCode) print(error.errorInfo)
逻辑分支
分支的介绍
所谓的分支语句,就是if/switch/三目运算符等判断语句。
经过分支语句能够控制程序的执行流程。
if分支语句
Swift中的if语句和OC中的if语句仍是有区别的:
区别1:Swift中判断句能够不加小括号(),可是判断以后的执行语句必需要用大括号{}括起来;OC中判断语句必须加小括号(),若是判断以后的执行语句只有一句话的话能够省略大括号{}。
let g = 8if g>0 { print("正数")}
区别2:Swift的判断句中必需要有明确的真假,必需要有明确的布尔值,Swift中再也不有非0即真的概念;OC中是非0即真、非空即真。
三目运算符
Swift中的三目运算与OC中保持了一致的风格。
let a = 10;let b = 20; //打印较大值print(a > b ? a : b);
guard的使用
guard语句与if语句很是相似,可是与if语句不一样的是,guard语句当条件为false的时候才会执行{}里面的代码。
guard语句必须带有else语句,他的语法以下:
guard 条件表达式 else { //当条件表达式不成立的时候执行的语句 break} 语句组
另一个须要说明的点是,guard语句必须放在函数中。
func online(age : Int) -> Void { guard age >= 18 else { print("未成年人不能上网") return } print("能够上网")} online(age: 17)
Switch-case语句
switch做为选择语句中必不可少的语句也被加入到了Swift中。
首先看一个例子:
/** case区间*/let a = 100 switch a {case ..<60: print("不及格")case 60..<80: print("合格")case 80..<90: print("良好")case 90...100: print("优秀")default: print("天才")} /** 一个case能够判断多个值,多个值以,隔开*/let b = 0 switch b {case 0,1: print("正常人")default: print("其余")} /** fallthrough关键字进行穿透* 所谓的穿透是指,当这个case知足的时候,执行完这个case所对应的内容以后,* 不会跳出,而是接着执行紧挨着的下一个case所对应的内容*/let c = 0 switch c {case 0: fallthroughcase 1: print("正常人")default: print("其余")} /** switch是支持多种数据类型的* 不但支持整型、区间,还支持浮点型、字符串等。*/let d = 10let e = 5var result = 0 let opration = "+" switch opration {case "+": result = d + ecase "-": result = d - ecase "*": result = d * ecase "/": result = d / edefault: result = 0}
Swift中的case后面的语句块执行完毕以后能够不跟break,由于默认会有break。
循环
在C/OC中,常见的循环有for/while/do-while;在Swift中,对应的循环有for/while/repeat-while。
For循环
for循环分为两种,一种是传统的C语言风格的for循环,以下:
for var i = 0; i < 10; i++ { print(i)}
这种传统写法,在Swift3中已经被淘汰了,以下:
还有一种是for-in循环,以下:
for i in 0..<10 { print(i)}
关于for-in循环,有一个特殊的地方须要注意:若是在某个循环中不须要用到下标i,那么使用下划线来代替下标,以下所示:
for _ in 0..<10 { print("Swift")}
否则的话会有以下的警告⚠️:
while循环和repeat-while循环
//while循环(先判断,再执行)var a = 0 while a < 10 { print(a) a+=1} //repeat-while循环(先执行一次,再判断)var a = 0 repeat { print(a) a += 1} while a < 0
Swift中的repeat-while循环与OC中的do-while循环其实如出一辙,均可以保证至少执行一次。
字符串
OC和Swift中的字符串是有区别的:
字符串的定义
//不可变字符串let str1 = "不可变字符串" //可变字符串var str2 = "可变字符串"str2 = "我变变变" //多行字符串var str3 = """多行字符串第一行第二行第三行第四行56"""
上面介绍了了几种传统的字符串定义形式,接下来咱们来聊聊Swift5.0以后新推出的Raw String(原始字符串)。
Raw String 是使用 # 来包裹字符串,其最大的特色就是:它不会对反斜杠进行特殊的转义处理。
当字符串中含有双引号或者反斜杠转义符的时候,使用传统的方式定义以下:
let var1 = "若是句子中有双引号""就会很尴尬"//输出:若是句子中有双引号""就会很尴尬let var2 = "若是句子中有转义字符就会很尴尬"//输出:若是句子中有转义字符就会很尴尬
使用Swift5.0新推出的RawString定义以下:
let var1 = #"若是句子中有双引号""就会很尴尬"#let var2 = #"若是句子中有转义字符就会很尴尬"#
若是字符串是被#包裹,那么 是不须要转义的。
那若是字符串中有#,那怎么办呢?答案是使用两个井号##来包裹:
let var1 = ##"若是句子中有井号#"##//打印结果:若是句子中有井号#
字符串的经常使用操做
//计算字符串的长度 let str = "12345678" print(str.count) print((str as NSString).length) //拼接两个字符串 var str1 = "Norman" + "Lee" var str2 = str1.appending("666") //遍历字符串(字符串能够当作是多个字符的集合) let str = "abcdefg" for char in str { print(char) } //字符串中是否包含某子字符串 let str = "abcdefg" print(str.contains("abc")) //true print(str.contains("A")) //false print(str.contains("h")) //false //分割字符串 let str = "abc&def&ghi&jkl&mn" let desc = str.components(separatedBy: "&") // ["abc", "def", "ghi", "jkl", "mn"] for item in desc { print(item) } //字符串替换 let str = "abc&def&ghi&jkl&mn" let result = str.replacingOccurrences(of: "&", with: "---") print(result) // abc---def---ghi---jkl---mn
数组
数组是一堆有序的由相同类型的元素构成的集合。
数组中的元素是有序的,能够重复出现。
Swift用Array表示数组,它是一个泛型集合。
数组的初始化
数组分为可变数组和不可变数组:
//定义一个可变数组 var arrar1 : [String] = [String]() //此时定义的是一个空数组 //定义一个不可变数组 let array2 : [String] = ["Norman", "Lavie"]
声明一个Array类型有以下两种写法,能够任选其一:
//语法糖var array1 : [String] var array2 : Array<String>
声明的数组须要进行初始化才能使用,数组类型每每是在声明的同时进行初始化的:
//定义的同时直接进行初始化 var array1 = ["Norman", "Lavie"] //先定义,而后初始化 var array2 : Array<String> array2 = ["Norman", "Lavie"]
注意区分<u >数组和元组</u>。
数组的基本操做
var array = ["Norman", "Lavie", "绪雨成澜"] //获取长度 array.count // 3 //判空 array.isEmpty // false //尾部添加元素 array.append("大鱼") // ["Norman", "Lavie", "绪雨成澜", "大鱼"] //指定位置插入元素 array.insert("Bruce", at: 1) // ["Norman", "Bruce", "Lavie", "绪雨成澜", "大鱼"] //删除元素 array.remove(at: 0) array.removeLast() array.removeFirst() //修改元素 array[0] = "小李" //取值(直接经过下标索引取值) print(array[0]) print(array[1]) //倒序 array.reverse()
数组的遍历
var array = ["Norman", "Lavie", "绪雨成澜", "大鱼"] //for-in遍历下标 for i in 0..<array.count { print(array[i]) } //for-in遍历元素 for name in array { print(name) } //遍历某区间内的元素 for name in array[0...2] { [print(name)] } //元组方式的遍历(若是既须要拿到索引又须要拿到元素,推荐使用该方式) for (index, name) in array.enumerated() { print(index) print(name) }
数组的合并
var array1 = ["Norman", "Lavie"] var array2 = ["绪雨成澜", "大鱼"] array1 += array2 print(array1) // ["Norman", "Lavie", "绪雨成澜", "大鱼"]
虽然仅仅用一个加号就能够实现数组的合并,可是必定要保证一点:要合并的两个或者多个数组的元素类型必需要保持一致。
字典
字典是由键值对(key:value)组成的集合,它由两部分集合构成:一个是键集合,一个是值集合。字典是经过访问键来间接访问值的,键集合中是不能够有重复元素的,而值集合中的元素是能够重复的。
字典中的元素是无序的。
Swift中的字典类型是Dictionary,是一个泛型集合。
字典的初始化
在Swift中,使用let修饰的字典是不可变字典,使用var修饰的字典是可变字典:
//定义一个可变字典 var dic1 : [String : Any] = [String : Any]() //定义一个不可变字典 let dic2 : [String : Any] = ["name" : "Norman", "age" : 28]
在声明一个字典的时候,有下面两种方式,能够任选其一:
var dic : [String : Any] var dic : Dictionary<String, Any>
跟数组同样,声明的字典也是须要初始化以后才能使用:
//声明的同时进行初始化 var dic1 : [String : Any] = [String : Any]() //先声明,后初始化 var dic : Dictionary<String, Any> dic = ["name" : "Norman", "age" : 28]
额外说一点,在Swift中,任意类型是使用Any来表示的。
字典的基本操做
var dict : [String : Any] = ["name" : "Lavie", "age" : 18, "gender" : "male"] //长度 print(dict.count) //判空 print(dict.isEmpty) //添加元素 dict["height"] = 178 dict["weight"] = 65 /* * 须要注意的是,上面添加元素的这种方式,若是Key值不存在,那么就是添加元素; * 若是Key值存在,那么就是修改元素 */ //删除元素 dict.removeValue(forKey: "age") // 删除指定元素 dict.removeAll() // 删除全部元素 //修改字典 dict["name"] = "Norman" // 方式一 dict.updateValue("大鱼", forKey: "name") // 方式二 //查询字典 print(dict["name"])
字典的遍历
var dict : [String : Any] = ["name" : "Lavie", "age" : 18, "gender" : "male"] //遍历字典中全部的Value值 for value in dict.values { print(value) } //遍历字典中全部的Key值 for key in dict.keys { print(key) } //遍历全部的键值对 for (key, value) in dict { print(key) print(value) }
字典的合并
前面讲的字符串和数组,都是能够直接使用加号+来进行合并的,可是这一点对于字典并不适用。字典是不能够直接使用加号+来进行合并的。
字典应该使用以下方式来合并:
var dict1 : [String : Any] = ["name" : "Lavie", "age" : 18, "gender" : "male"]var dict2 : [String : Any] = ["height" : 178, "weight" : 65]for (key, value) in dict2 { dict1[key] = value}print(dict1) // ["gender": "male", "age": 18, "weight": 65, "height": 178, "name": "Lavie"]
可是这种合并字典的方式须要特别注意,若是有Key重名,那么该Key在原字典中所对应的Value值将被新字典中所对应的Value值覆盖。
可选型
在OC中,若是一个变量暂时不使用,能够赋值为0(基本数据类型)或者赋值为nil(对象类型)。在OC中,nil就表示一个空指针,它并不做为一个特殊的类型。
在Swift中,nil是一个特殊的类型,它与Int、String同样,都是一种类型。而且Swift语言又是一种强类型语言,所以不能直接将nil赋值给其余类型的数据。
在开发中,碰到nil在所不免,所以Swift推出了可选类型。
可选类型的取值有以下两种:
定义可选类型
//写法一:官方定义方式 var a : Optional<Int> = 6 // 有值 a = nil // nil //写法二:语法糖(直接在类型后面加问号?) var b : Int? = 8 // 有值 b = nil // nil
可选类型的使用
给可选类型赋值:
// 定义可选类型 var name : String? = nil //给可选类型赋值 name = 123 // ❌错误写法,可选类型也是有类型校验的,这里只能复制字符串,赋值其余类型都会报错 name = "norman" // 正确 // 打印结果 print(name) // Optional("norman") 由于是可选类型,因此会带Optional
取出可选类型的值(显性解包):
// 定义可选类型 var name : String? = "Norman" print(name) // Optional("norman") //取出可选类型的真实值 //使用!强制解包(显性解包) print(name!) // Norman //若是可选类型为nil,强制解包会出错 name = nil //print(name!) // 报错:Unexpectedly found nil while unwrapping an Optional value //正确写法应该先判空 if name != nil { print(name!) }
取出可选类型的值(隐式解包):
Swift中有一个if-let写法,if-let就是专门用于作可选绑定(隐式解包)的,以下:
if let 常量 = 可选型 { //处理常量}
这里的【常量 = 可选型】语句的做用是:若是可选型的值不是nil,那么就将可选型的真实值传给常量,而且执行花括号{}里面的语句;若是可选型的值是nil,那么【常量 = 可选型】这个条件就不成立(由于不能直接给一个非可选型变量赋值为nil),那么就不会走到花括号里面的内容。
// 定义可选类型 var name : String? = "Norman" /* *可选绑定(隐式解包) */ if let nameString = name { print(nameString) }
强烈推荐使用可选绑定来对可选型进行隐式解包!
类型转换
基础数据类型转换
好比Double转Int,Int转Float等,只须要使用数据类型(待转类型)便可:
//Int转Double var a : Int = 6 var b : Double = Double(a) //Float转Int var c : Float = 8.99 var d : Int = Int(c)
基础类型与字符串转换
//字符串插值能够直接将基础类型转换成字符串 var age : Int = 6 var str = "小明今年(age)岁了" //字符串转成基本类型,必需要保证字符串的内容是能够转换的 var string = "123" var d = Int(string)
函数
Swift中的函数,其实就至关于Objective-C中的方法。函数的格式以下:
func 函数名(参数,列表) -> 返回值类型 { 代码块 return 返回值}
有如下几点说明:
1,func 是定义函数的关键字
2,参数列表中的多个参数之间,可使用英文逗号 , 分割,也能够没有参数
3,使用 -> 指向返回值类型
4,若是函数没有返回值,则 -> 返回值类型 部分能够省略
常见的函数类型
没有参数,没有返回值:
//写法一:官方标准写法 func drinkWater() -> Void { print("drink water 111") } //写法二:若是没有返回值,Void能够写成() func drinkWater1() -> () { print("drink water 222") } //写法三:若是没有返回值,后面的内容能够都不写 func drinkWater2() { print("drink water 333") } //调用函数 drinkWater() drinkWater1() drinkWater2()
有参数,没有返回值:
func call(phoneNumber : String) { print("加入iOS交流群(phoneNumber)")}call(phoneNumber: "642363427")
没有参数,有返回值:
func myName() -> String { return "norman"}let name = myName()
有参数,有返回值:
func plus(a : Int, b : Int) -> Int { return a + b;}let result = plus(a: 3, b: 3)
函数的使用注意
1,每个函数的形式参数都包含形式参数标签和形式参数名两部分
//这里的info1和info2就是形式参数标签 //name和age是形式参数名称 func personalInfo(info1 name : String, info2 age : Int) { //在函数的实现中使用形式参数名称 print("姓名:(name),年龄:(age)") } //在函数调用的时候使用形式参数标签 personalInfo(info1: "norman", info2: 23) //下面是默认写法 //此时,name和age既是形式参数标签,也是形式参数名称 func personalInfo(name : String, age : Int) { //在函数内部实现的时候,name和age是形式参数名称 print("姓名:(name),年龄:(age)") } //在函数调用的时候,name和age是形式参数标签 personalInfo(name: "norman", age: 24) //若是不想要形式参数标签,能够在形式参数名称前面加 _ func personalInfo(_ name : String, _ age : Int) { print("姓名:(name),年龄:(age)") } //在函数调用的时候,没有形式参数标签 personalInfo("norman", 24)
2,能够给函数的参数设置默认值
//若是不想要形式参数标签,能够在形式参数名称前面加 _ func personalInfo(_ name : String = "lavie", _ age : Int = 28) { print("姓名:(name),年龄:(age)") } personalInfo() // 姓名:lavie,年龄:28 personalInfo("norman", 24) // 姓名:norman,年龄:24
3,指针的传递
默认状况下,函数的参数是值传递。若是想改变外面的变量,则须要传递变量的地址。
//交换值 func swapInt(a : inout Int, b : inout Int) { let temp = a a = b b = temp } var a = 6 var b = 8 print("a=(a), b=(b)") // a=6, b=8 swap(&a, &b) // 将地址传递进来 print("a=(a), b=(b)") // a=8, b=6
函数的类型
咱们以前介绍的数组Array、字典Dictionary等,都是值类型,而函数是引用类型。
每一个函数都有属于本身的类型,一个函数的类型是由该函数的参数类型和返回类型决定的。
有了函数类型之后,就能够把函数类型像Int、Array同样来使用了。
下面的例子定义了additionMethod和multiplicationMethod两个函数,这两个函数都传入了两个Int类型的参数,返回一个Int类型值,所以这两个函数的类型都是(Int, Int) -> Int
func additionMethod(a : Int, b : Int) -> Int { return a + b;} func multiplicationMethod(a : Int, b : Int) -> Int { return a * b;}
接下来咱们来看一下函数的简单赋值:
//初始化一个函数类型变量,并赋初始值 var mathMethod = additionMethod mathMethod(2, 3) // 5 //给函数类型变量赋其余值 mathMethod = multiplicationMethod mathMethod(2, 3) // 6
函数也能够做为一个函数的参数:
func additionMethod(a : Int, b : Int) -> Int { return a + b; } func multiplicationMethod(a : Int, b : Int) -> Int { return a * b; } //函数做为参数 func printResult(a : Int, b : Int, mathMethod : (Int, Int) -> Int) { print(mathMethod(a, b)) } printResult(a: 3, b: 4, mathMethod: additionMethod) // 7 printResult(a: 3, b: 4, mathMethod: multiplicationMethod) // 12
函数还能够做为一个函数的返回值:
func additionMethod(a : Int, b : Int) -> Int { return a + b; } func multiplicationMethod(a : Int, b : Int) -> Int { return a * b; } //函数做为返回值 func mathMethod(a : Int) -> (Int, Int)->Int { if a > 10 { return additionMethod } return multiplicationMethod } var resultMethod = mathMethod(a: 11) resultMethod(6, 8) // 14