前言
最近开始看下《Swift4从零到精通iOS开发》,学习下Swift的语法.也相当于做一个简单的读书笔记.
虽然在毕业前也做过一丢丢的Swift语法学习,但是那个时候还没有接触到任何的iOS开发,当时学起来也是晦涩难懂,所以之前的学习就当作空白归零,现在重新开始新的Swift语法学习.
量值与基本数据类型
特殊的基本数据类型
- 元组
元组是Swift中特有的数据类型,允许一些不相关的数据类型进行自由组合成为新的集合类型.如下定义1
2
3
4
5/// note Swift中对于string类型前面不需要加@
var pen:(name:String,price:Int) = ("钢笔",2)
/// 进行元组定义后,可以使用通过参数名称来取得各个参数
var name = pen.name; //钢笔
var price = pen.price; //2
在创建元组时,可以不指定元组中的参数名称,此时元组会自动为每个参数分配下标,从0开始
1 | var newpen:(String,Int) = ("钢笔",2) |
元组分解,元组创建后,可以通过制定变量为分解.
1 | var newpen:(String,Int) = ("钢笔",2) |
在上面代码中,使用_来表示匿名的概念,因此只分解了第一个参数
- 可选值类型
optional类型是Swift特有的一种类型,在实现Swift类型安全上,使用Optional对普通类型进行包装,实现对空值的监控.在Swift中,如下代码会在编译时报错,1
2
3
4
5//Variable 'obj' used before being initialized
var obj:String
if obj == nil {
obj = "111";
}
在Swift中如果需要基本类型为nil的话,应该将其包装为Optional类型.
1 | var obj:String? |
Optional是对普通类型的一种包装,在使用时也需要拆包操作.拆包使用操作符”!”
1 | var obj:String? |
字符,字符串和集合类型
字符串类型
在Swift中,String类型是一个结构体,结构体中定义了属性和方法.String中提供了很多的重载构造方法.
1 | var str:String = "123"; //使用字符串初始化 |
var str1 = "hello";
var str2 = "world";
/// 注意重载运算符+两边不能有空格
str1 = str1+" "+str2;
print(str1);
1 |   可以使用插值的方式对字符串进行组合拼接.这种方式**在开发中经常使用** |
var str3 = "hello\(123)"
var str4 = "hello \(str2)"
print(str3,str4); // hello123 , hello world
1 | #### 字符串类型中的常用方法 |
var sstr = "hello-swift"
var startIndex = sstr.startIndex; ///起始索引,不是一个integer
var endIndex = sstr.endIndex; /// 结束索引,不是一个integer,注意,此处返回结束位置的下一个位置
var lenth = sstr.count; /// 字符串长度 11
var char = sstr[sstr.index(after: startIndex)]; /// 第二个字符 e
var char2 = sstr[sstr.index(before: endIndex)]; /// 最后一个字符 t
print(char,char2); ///e t
var range = sstr.range(of: "hello") ///子串所在的位置
sstr.append("!") /// hello-Swift!
print(sstr)
sstr.insert("1", at: sstr.endIndex) /// hello-Swift!1
print(sstr)
sstr.insert(contentsOf: ["1","1","1"], at: sstr.endIndex) /// hello-Swift!1111
sstr.remove(at: sstr.index(before: sstr.endIndex)) /// hello-Swift!111
print(sstr)
sstr.hasPrefix("hell") ///是否有前缀 yes
sstr.hasSuffix("222") ///是否有后缀 no
sstr.uppercased() ///转大写
sstr.lowercased() ///转小写
1 | #### 集合类型 |
///申明空数组
var arr1:[Int] = []
var arr2:Array
arr1 = [1,2,3]; // [1,2,3]
arr2 = Array(arrayLiteral: 1,2,3) [1,2,3]
1 |   数组相加 Swift中对数组的+运算符也进行了重载,但是要保证相加的数组元素类型相同 |
var arr3 = [1,2,3]+[4,5,6] //[1,2,3,4,5,6]
1 |   数组中的常用方法 |
arr3.count; /// 个数
arr3.isEmpty /// 是否空
arr3.first; /// 第一个元素
arr3.last; ///最后一个元素
arr3.append(7); ///[1,2,3,4,5,6,7]
arr3.removeLast() /// [1,2,3,4,5,6]
arr3.removeLast(2) /// [1,2,3,4]
arr3.max() /// 最大值
arr3.min() /// 最小值
1 | - Set集合 |
var set1:Set<Int> = [1,2,3,4]
var set2:Set<Int> = [3,4,5,6]
var setInter = set1.intersection(set2) //[4, 3] 交集
var setEx = set1.symmetricDifference(set2) // [6, 5, 1, 2] 交集的补集
var setUni = set1.union(set2) /// 并集 [4, 5, 6, 1, 3, 2]
var setSub = set1.subtracting(set2) /// 差集 [1,2]
print(setInter,setEx, setUni,setSub)
1 |
|
var q:Int? = 8
var value:Int
if q != nil {
/// 不为空,拆包
value = q!
} else {
/// 为空,赋值0
value = 0
}
/// 使用空合并运算符
var q:Int? = 8
var value:Int
value = q ?? 0 /// 8
1 |   空合并运算符会自行判断是否为空,并自行拆包.**注意:??两边需要有空格** |
var srange = 0...10
var srange2 = 0..<10
// var range3 = 0<..10 ///报错,没有左开区间
print(srange,srange2)
1 |
|
var ssstr:String = "111"
switch ssstr {
case "111":
print(sstr) ///自动break
case "333":
print("333")
default:
print("222")
}
1 | - fallthrough:fallthrough可以使switch语句继续向下执行,不直接跳出 |
var ssstr:String = "111"
switch ssstr {
case "111":
print(sstr) ///自动break
fallthrough
case "333":
print("333")
fallthrough
default:
print("222") /// log 111 333 222
}
1 | - guard else 守护语句:作用是只在某个条件成立时才执行相应代码,类似if的效果 |
func foo(params:Int) {
if params>0 {
print(params)
} else {
return
}
}
/// guard
func foo2(params:Int) {
/// params <= 0 直接返回
guard params>0 else {
return
}
print(params)
}
1 | ### 函数 |
/// params1不定参数,但是类型一致
func foo3(params1:Int ...,params2:String) -> Int {
var sum:Int = 0;
for cout in params1 {
sum += cout
}
print("foo3",sum)
return sum
}
1 | - Swift中如果是值传递,不能修改参数在函数内部的值.在Swift中类是引用类型,基本数据类型(枚举,结构体,float...)是值类型,如果需要修改值类型的参数,需要添加**inout**关键字,同时引用传递参数 |
func foo4(params:Int) -> Int {
params = params+1; ///不能修改params
return params
}
/// 正确
func foo4(params:inout Int) -> Int {
params = params+1;
return params
}
1 |
|
func foo4(params:Int) -> Int {
return params*params
}
let myClosure = {(params:Int)->Int in
return params*params
}
foo4(3) /// 9
myClosure(3) /// 9
/// 1、闭包返回值类型可以通过定义自动推断
let myClosure2 = {(params:Int) in
return params*params
}
myClosure2(3) /// 9
1 | - 闭包作为函数参数 |
/// sortClosure 作为参数传递,进行数组排序
func mySort(array:inout Array
for indexI in array.indices {
if indexI == array.count-1 {
break
}
for indexJ in 0 … ((array.count - 1) - indexI - 1) {
if sortClosure(array[indexJ] as! Int, array[indexJ+1] as! Int) {
} else {
array.swapAt(indexJ, indexJ+1)
}
}
}
return array
}
/// 调用
mySort(array: &tmpArray, sortClosure: {(index:Int,index2:Int) -> Bool in
return (arrays[index] as!Int) <= (arrays[index2] as!Int)
})
1 | - 闭包的写法优化 |
///省略返回类型,编译器自动通过闭包返回类型推断
mySort(array: &tmpArray, sortClosure: {(index:Int,index2:Int) in
return (arrays[index] as!Int) <= (arrays[index2] as!Int)
})
/// 如果闭包只有一行代码,同时闭包作为函数的参数,闭包的return关键字可以省略
mySort(array: &tmpArray, sortClosure: {(index:Int,index2:Int) in
(arrays[index] as!Int) <= (arrays[index2] as!Int)
})
/// 当闭包围坐函数的参数时,闭包的参数列表会自动创建一组参数,参数名以$0,$1这样的结构类推,因此
mySort(array: &tmpArray, sortClosure: {
(arrays[$0] as! Int) <= (arrays[$1] as!Int)
})
1 | - 后置闭包 |
///后置闭包写法
mySort(array: &tmpArray) {
(arrays[$0] as! Int) <= (arrays[$1] as!Int)
}
1 |   当函数之后一个参数,并且参数时比好类型时,可以用后置闭包的写法省略函数的参数 |
/// 定义
func foo5(myClosure:(Int,Int)->Bool){
}
/// 调用
foo5 {
$0<=$1
}
1 | - 逃逸闭包和非逃逸闭包 |
func adds(params1:Int,params2:Int)->Int {
}
func adds(params1:String,params2:Int)->String {
}
1 |
|
/// 前缀++
prefix operator ++
prefix func ++(params:Int) -> Int {
var ret = params
ret = ret+1
return ret
}
/// 中缀运算符重载
infix operator ++
func ++(params:Int,params2:Int) -> Int {
return (params * params2)
}
/// 后缀运算符重载
postfix operator ++
postfix func ++(params:Int) -> Int {
return params+1
}
1 | #### 枚举的创建和应用 |
/// 声明字符枚举
enum charEnum:Character {
case a = “a”
case b = “b”
case c = “c”
}
1 |
|
enum shape {
case circle(center:(Double,Double),radius:(Double))
case rectangle(center:(Double,Double),width:(Double),height:(Double))
case triangle(point1:(Double,Double),point2:(Double,Double),point3:(Double,Double))
}
1 | 然后使用switch语句时根据样式进行匹配. |
class MyClass {
var count:Int = 0 {
willSet {
print(“willSet:count”)
}
didSet {
print(“didSet:count”)
}
}
init(params:Int) {
count = params
}
}
var objClass = MyClass(params: 5)
objClass.count = 3; ///只有在初始化后赋值才会触发属性监听
1 |
|
class subCheck:check {
var subProperty:Int
init() {
/// 原则1调用父类构造方法前,先完成自身属性赋值
subProperty = 1;
super.init(param: 0);
/// 原则2 如果子类对父类属性重新赋值,需要在父类初始化方法之后,保证父类已经存在
property = 2;
/// 原则3完成父类构造方法之后,才能使用self关键字
self.subProperty = 3;
}
convenience init(param1:Int,param2:Int) {
self.init();
/// 原则4 便利构造方法中要修改属性的值需要在指定构造方法之后,防止值被覆盖
subProperty = 3;
property = param2;
}
}
1 |
|
class reCheck {
var property:Int
/// 可失败构造方法
init?(params:Int) {
guard params>10 else {
return nil
}
property = params;
}
/// 此构造方法必须子类实现
required init(param1:Int,param2:Int) {
property = param2;
}
deinit {
print(“该类被销毁”);
}
}
```
与构造方法相对应的是析构方法.使用deinit标识,当把实例置为nil时,实例会被释放