Swift自学笔记

swift自学笔记

该笔记为自学swift的学习笔记,以便后续查阅复习


Swift

基础知识

1.变量常量定义:
  • var 定义变量

  • let 定义常量

    var a:String = "Hello world"
    let b:Int = 8
    let c:Character = "A"
    
2.判断数据类型
  • type(of: )

    type(of:a)
    //判断a的数据类型
    
3.输出语句
  • print()

    print(a,b)
    //输出结果:Hello world 8
    
4.拼接字符串
  • ()语法 和 +号语法

    print(a + "\(b)")
    print(a + " \(b)")
    //分别输出结果:
    //Hello world8
    //Hello world 8
    
5.类型别名
  • typealias 将类型取一个简易的别名

    typealias S = String
    var c:S = "hello"
    
6.类型转换
  • 强制类型转换:类型()

    var a = 10
    print("值等于 = " + String(a))
    //输出结果:值等于 = 10
    
  • ??语法:

    看所输出的内容是否有值,如有值输出自身的值,若没有值则输出??后 的值

    var a = "hello"
    print(Int(a) ?? 10)
    //输出 10
    
7.可选类型
  • ?语法 | var a : Int? = nil:

    a是一个Int类型的变量,可能有值可能没有值,没有值的情况下就是nil

    var a:Int? = nil
    var b:Int? = 10
    print(a)
    print(b)
    print(a ?? 100)
    print(b ?? 0)
    //nil
    //Optional(10)
    //100
    //10
    
  • !语法:

    输出的时候明确当前的变量有值

    var a:Int = 100
    print(a!)
    //100
    var b:Int = nil
    print(b!)
    //运行的时候会报错
    
8.元组类型
1.元组的定义
  • var a = (1,15.6,“hello”,true)

  • var b:(Int,String) = (10,“Hello”) //如果前面定义了元组类型格式,后面就不能写一个空元组

  • var c = () //表示空元组

    var a = (1,12.3,"hello",true)
    print(a.1)
    //输出结果为12.3
    a.0 = 100
    print(a.0)
    //输出结果为100
    
2.元组的传递
 var a = (1,12.3,"hello",true)
 var b = a
 print(a)
 print(b)
 //(1,12.3,"hello",true)
 //(1,12.3,"hello",true)
 b.2 = "world" //元组的传递是值传递
 print(b)
 (1,12.3,"world",true)
3.元组的取名定义
var a = (name1:"hello",name2:10)
print(a)
print(a.name1)
//(name1:"hello",name2:10)
//hello
4.元组在声明变量的时取名
var a:(name1:Int,name2:String) = (100,"hello")
print(a)
print(a.name1)
//(name1:100,name2:"hello")
//100
5.元组中忽略部分value
let a:(name1,_,name2) = ("swift",23,10.5)
print(a.name1,a.name2)
//swift 10.5
6.元组可以当作函数中的参数
var data = (name1:1,name2:"hello",name3:true)
func handle(parm:(Int,String,Bool)) -> (Int,String,Bool)
{
    var data_temp = parm
    data_temp.0 = parm.0 + 1
    data_temp.1 = parm.1 + " world"
    data_temp.2 = false
    return data_temp
}
print(data)
print("--------------------------------------")
let data2 = handle(parm:data)
print(data2)
/*
输出结果:
(name1:1,name2:"hello",name3:true)
--------------------------------------
(2,"hello world",false)
*/
9.运算符
1.逻辑运算符
  • 逻辑与:&&
  • 逻辑或:||
  • 逻辑非:!
2三元运算符
  • a ? b : c

    用法和其他编程语法用法相同,a为真取b值,a为假取c值

3.合并空值运算符:??

​ 看所输出的内容是否有值,如有值输出自身的值,若没有值则输出??后 的值

4.区间运算符
  • a = 1…4 //范围等于1到4
  • b = 1…<4 //范围等于1到3
  • c = -3…<4 //范围等于-3到3
  • d = 0… //范围等于0到正无穷
10.隐式展开

用在a有值的情况下

var a:Int! = 100 //确定a有值 在Int后写一个!
var b:Int = a //这里进行传递的时候,b也要定义类型
print(b)
//100

提问:为什么当a都已经确定有值了,还需要写个!多此一举?

因为如果a直接等于100之后,就没办法再修改为nil了,而如果通过!确定为100的方式,则还可以将a修改为nil值

11.if语句
1.基本格式
var a = 10
if(a < 10)
{
    print("a小于10")
}
else if(a == 10)
{
    print("a等于10")
}
else
{
    print("a大于10")
}
2.可选项绑定if语句
var a:Int? = 10
if (let value = a)//如果a有值就会传递给value,然后通过value的值来运行if判断,这里不需要!号解析a
{
    print("value的值= \(value)")
}
else 
{
	print("value没有值")    
}
12.switch case语句
  • 通常情况
var a = 10

switch a
{
case 10:
    print("情况1")
case 20:
    print("情况2")
case 30:
    print("情况3")
default:
    print("没有匹配")
}
  • 一个case块可以匹配多个值
//  键入一个方向键,判断时哪个方向
func judgeDirection(inputCharacter: Character) {
        switch inputCharacter {
        case "a", "A":
            print("左移")
        case "w", "W":
            print("上移")
        case "d", "D":
            print("右移")
        case "s", "S":
            print("下移")
        default:
            print("您输入的不是方向键")
        }
    }
  • case判断条件为区间运算符
var a = 7
	
   	switch a {
        case 1..<6: //或 case 1...6:
                print("情况1 ")
                
        case 6..<10://case 6...10:
                print("情况2")
               
            default:
                print("未能匹配")
        }
  • case匹配元组 && where语句可以增加条件判断
/*
这里定义一个函数用来判断输入的点位位于坐标系的位置,
参数即为需要判断位置的点位。(Float, Float)为Swift中的元组类型,这里暂时不去深究。
返回值即为坐标点坐在象限。
*/
func judgePosition(position: (Float, Float)) -> String {
        switch position {
        case (0, 0):
            return "(0, 0)位于原点"
        case (let x, 0):
            return "(\(x), 0)点位于x轴"
        case (0, let y):
            return "(0, \(y))点位于y轴"
        case let (x, y) where x > 0 && y > 0: 
            //注意此处let写在()外,let一整个元组对象
            return "(\(x), \(y))点位于第一象限"
        case let (x, y) where x < 0 && y > 0:
            return "(\(x), \(y))点位于第二象限"
        case let (x, y) where x < 0 && y < 0:
            return "(\(x), \(y))点位于第三象限"
        case let (x, y) where x > 0 && y < 0:
            return "(\(x), \(y))点位于第四象限"
        default:
            return "恭喜你,这是一个异次元的点位~"
        }
    }
print(judgePosition(position: (1.4, 1.5)))
//输出: (1.4, 1.5)点位于第一象限
  • 显式贯穿 fallthrough

简单的来说就是在满足条件的case块中有fallthrough字段,则继续向下执行一个case(不管下一个case条件如何,都执行),并将结果一同输出

 var b = 10

    print("含有fallthrough:")

    switch b {
        case 10:
            print("情况1")
            fallthrough
            
        case 20:
            print("情况2")
            
        default:
            print("未能匹配")
/*输出结果:
	含有fallthrough:
	情况1
	情况2
*/
13. for in循环
  • 常规格式for循环
for index in (0...5) {
    print(index)
}
  • 跳步for循环(使用stride函数)

​ 1.不包括结尾 **stride(from : x,to: y,by: n ) ** 范围:[x,y),步长为n

for index in stride(from: 0, to: 10, by: 2) {
    print(index)
}
/*输出:
0
2
4
6
8
*/

​ 2.包括结尾 **stride(from : x,through: y,by: n ) ** 范围:[x,y],步长为n

for index in stride(from: 0, through: 10, by: 2) {
    print(index)
}
/*输出:
0
2
4
6
8
10
*/

​ 3.反向取值输出,在最后加上 **.reversed() **函数

for index in stride(from: 0, through: 10, by: 2).reversed() {
    print(index)
}
/*输出:
10
8
6
4
2
0
*/

​ 4.continue 和 break

  • continue 跳过本次遍历,进入下一轮循环
  • break 跳出本次for循环
14.while循环
var a = 0
while(a < 5)
{
	print(a)
    a=a+1
}
/*输出
0
1
2
3
4
*/
15.repeat while循环 | 相当于其他编程语言的do while循环
var a = 0
repeat
{
	print(a)
    a=a+1
}
while(a < 5)
/*
输出:
0
1
2
3
4
*/
16.Array数组(有序数组)
  • 常见的几种定义方式
var a = [1,2,3,4]
print(a)
//[1,2,3,4]
var b:String  = ["hello","world"]
print(b)
//["hello","world"]
var c:Array<Double> = [1.4,1.5]
print(c)
//[1.4,1.5]
  • 常见的基本操作 | 增删改查
//增加
var a = ["hello","world"]
a = a + ["ios","macos"]
print(a)
//["hello","world","ios","macos"]

a.append("iPhone") //在最后添加新的元素
print(a)
//["hello","world","ios","macos","iPhone"]

a.insert("macbook",at:2) //在指定索引位置插入新数据
print(a)
//["hello", "world", "macbook", "ios", "macos", "iPhone"]


//删除
a.remove(at:2) //删除指定索引位置上的数据
print(a)
//["hello", "world", "ios", "macos", "iPhone"]


//修改
var c:Array<Double> = [1.4,1.5]
c[0] = 12.5
print(c[0])
print(c[1])
//12.5
//1.5

//将指定范围内的数据替换成指定的元素
var a = ["hello", "world", "ios", "macos", "iPhone"]
a.replaceSubrange((1...3), with:["windows"]) 
print(a)
//["hello","windows", "iPhone"]

//查找
var a = ["hello", "world", "ios", "macos", "iPhone"]
var b = a.contains("macos")
print(b)
//true
  • 常用的定义空的数组
var a:Array<Int> = []
print(a)
//[]
  • 使用初始化器定义数组
//通过初始化器,定义可变的空数组
var b = [Int]()
print(b)
//[]

//通过Array初始化器,生成一个初始值位-1,长度为3的数组
var c = Array(repeating:-1,count:3) 
print(c)
//[-1,-1,-1]
c[0] = 100
print(c)
//[100,-1,-1]
  • 注意情况
//用let定义的常量,不可添加元素,不可修改元素
let d = [1,2,3]
d.append(4) //在结尾加上元素4  会报错
d[0]=0  //将第一个元组改为0  会报错
  • 数组排序
//倒序排序
var a = ["A","C","D","B","F","E"]
a.sort(by: {(s1,s2) ->Bool in
    if(s1 > s2)
    {
        return true
    }
    else
    {
        return false
    }
})
print(a)
//["F", "E", "D", "C", "B", "A"]
  • 数组过滤
var a = ["A","C","D","B","F","E"]
var new_a = a.filter({(item) -> Bool in //需要传递给一个新数组
    if(item != "D")
    {
        return true
    }
    else
    {
        return false
    }
})
print(new_a)
//["A", "C", "B", "F", "E"]
  • 遍历数组
//常规遍历
var a = ["A", "B", "C", "D", "E", "F"]
for item in a
{
    print(item)
}
/*
A
B
C
D
E
F
*/

//用下标范围遍历
var a = ["A", "B", "C", "D", "E", "F"]

for  index in (0..<a.count)
{
    print(a[index])
}
/*
A
B
C
D
E
F
*/
//用下标范围遍历到无限大(到数组结尾)
var a = ["A", "B", "C", "D", "E", "F"]

for  index in (0...)
{
    print(a[index])
}
/*
A
B
C
D
E
F
*/
17.Set数组(无序数组)

基本与Array数组相同,在增删改查操作时,可以不用考虑指定下标位置

  • Set合并操作
var set_list:Set = ["hello","world"]
let data:Set = ["iphone","swift"]
var new_set = set_list.union(data) //合并操作
print(new_set)
//["hello","world","iphone","swift"]
  • 返回两个Set中相同数据 | 不同数据
//返回两个Set中相同数据
var set_list:Set = ["hello","world","swift"]
let data:Set = ["iphone","swift"]
var new_set = set_list.intersection(data) 
print(new_set)
//["swift"]

//返回两个Set中不同数据
var set_list:Set = ["hello","world","swift"]
let data:Set = ["iphone","swift"]
var new_set = set_list.symmetricDifference(data)
print(new_set)
//["world", "hello", "iphone"]

//返回前面Set中与后面Set中不同的数据
var set_list:Set = ["hello","world","swift"]
let data:Set = ["iphone","swift"]
var new_set = set_list.subtracting(data)
print(new_set)
//["hello","world"]
18.Dictionary字典集合

相当于也是一个无序的数组类型,每个值都有一个与之关联的唯一键作为该值在该字典中的唯一标识,字典中的键和值的类型必须是明确的,对字典的键的唯一限制是这个KeyType必须是可哈希的类型

格式:Dictionary<KeyType, ValueType>

  • 常见的创建方式
var a:Dictionary<String,String> = ["a":"A","b":"B"]
print(a)
//["b": "B", "a": "A"]

var a:[Int:String] = [1:"A",2:"B"]
print(a)
//[2:"B",1:"A"]

var a = [1:"A",2:"B"]
print(a)
//[2:"B",1:"A"]

//定义了一个空字典
var a = [Int:String]()
  • 基本操作
//取值
var a = [1:"A",2:"B"]
print(a[1] ?? "unknow")
//"A"

//修改值
var a = [1:"A",2:"B"]
a[2]="C"
print(a)
//[2: "C", 1: "A"]

//修改指定key上的值,如果key没有则添加上去
var a = [1:"A",2:"B"]
a.updateValue("C", forKey: 1)
print(a)
//[2: "B", 1: "C"]
a.updateValue("D", forKey: 3)
print(a)
//[2: "B", 1: "C",3:"D"]
  • 可选项绑定
var a = [1:"A",2:"B"]
if let item = a[1]
{
    print(item)
}
//A
//如果指定的key有返回值,就赋给item
//如果没有key就返回nil,不执行if语句
  • 遍历字典
var a = [1:"A",2:"B",3:"C"]
for (key,value) in a
{
    print(key,value)
}
/*
2 B
3 C
1 A
*/
19.枚举
  • 定义枚举
enum TestEnum
{
    case A
    case B
    case C
}
//或者
enum TestEnum
{
    case A,B,C
}
//获取枚举类型:
print(TestEnum.A)
//A
  • 设置枚举值
enum TestEnum:Int
{
    case A = 1
    case B = 2
}
print(TestEnum.A.rawValue)
print(TestEnum.B.rawValue)

//枚举相关值 |  调用方式
enum TestEnum
{
    case name(String)
    case age(Int)
    case xy(Int,Int)
}
func play(param:TestEnum)
{
    switch param {
    case TestEnum.name("hello"):
        print("hello")
    case TestEnum.age(10):
        print("10")
    case TestEnum.xy(20, 50):
        print("20,50")
    default:
        print("没有匹配")
    }
}
play(param: TestEnum.name("hello"))
play(param: TestEnum.age(10))
//hello
//10
  • 遍历枚举
enum Test:CaseIterable  //CaseIterable协议 swift5.0可用
{
    case A
    
    case B
    
    case C
}
print(type(of: Test))
//Array<Test>
for item in Test.allCases {
    print(item)
}
//A
//B
//C
20.Any和AnyObject

Any可以来创建任何类型,Anyobject只能创建class类,创建其他类都会报错

class Student
{
    var name:String
    init(name:String) {
        self.name =  name
    }
}

struct Data
{
    var data:String
    init(data:String) {
        self.data = data
    }
}

var a:Any = 1 //Any可以来创建任何类型
var b:Any = "hello"
var c:Any = Student(name:"sdsds")
var d:Any = Data(data:"dajskld")
var f:AnyObject = Student(name:"kdjaks") 
//Anyobject只能创建class类,创建其他类都会报错
print(type(of: a))
print(type(of: b))
print(type(of: c))
print(type(of: d))
print(type(of: f))
/*
Int
String
Student
Data
Student
*/

String基本操作

1.获得字符串长度 | .count
var a = "ABCDEF"
var b = "ABC DEF"
print(a.count)
print(b.count)
//输出:
//6
//7
2.取子字符
var a = "ABCDEF"
a.startIndex//字符的起始位置 第0位
a.endIndex//代表的是最后一个字符的后一位 第6位
print(a[a.startIndex]) //[]中一定要填一个String.Index值
print(a[a.index(after: a.startIndex))//a.startIndex往后一位
print(a[a.index(before: a.endIndex))//a.endIndex往前一位
//注意!这里endIndex往前取一位,取到的则是字符串的最后一个字符
print(a[a.index(a.startIndex, offsetBy:2)])//从startIndex位开始,第二位的字符串 因从下标0开始数,所以值为"C"
/*输出:
A
B
F
C
*/
3.取子字符串
  • 分别取头尾,然后通过区间运算符输出
var str = "ABCDEF"
var a = str.index(str.startIndex,offsetBy:2)
var b = str.index(str.startIndex,offsetBy:4)
print(str[a...b])
print(str[a..<b])
//输出:
//CDE
//CD
  • 从0位开始,打印到某个字符 | 需要Swift5.0
var str = "ABCDEF"
var c = str.firstIndex(of: "E") ?? str.endIndex 
//从0位开始打印到第一次出现“E”字符
print(str[str.startIndex...c])
//输出:
//ABCDE
  • 从0位开始,打印长度为n位字符 | str.prefix(n)
print(str.prefix(4))//打印从第0位开始,长度为4位字符串
//ABCD
  • 从末尾位置开始,倒取后n位字符串
//从末尾位置开始,倒取后2位字符串
let inde2 = str.index(str.endIndex,offsetBy:-2)
print(str[inde2..<str.endIndex])
//输出:
//EF
4.判断是否存在某个字符或字符串
  • Bool contains(element:Character) 判断是否存在单个字符
  • Bool contains(other:StringProtocol) 判断是否存在某个字符串
var str = "ABCDEF"
print(str.contains("A"))
print(str.contains("BCD"))
//输出:
//true
//true
  • 特殊情况:当母串包含一个字串中的字符,就返回true
var str = "ABCDEF"
print(str.contains(where:String.contains("KD")))
//输出:
//true
  • 判断字符串的前缀 后缀是否为某个字符串
    • 判断前缀 :str.hasPrefix(" ")
    • 判断后缀 :str.hasSuffix(" ")
var str = "ABCDEF"
print(str.hasPrefix("A"))
print(str.hasSuffix("EF"))
//输出:
//true
//true
5.追加字符串 | .append(" ")
var str = "ABCDEF"
str.append("hello swift")
print(str)
//输出:
//ABCDEFhello swift
6.插入字符串 | .insert(contentsOf: " ", at: String Index)
var str = "ABCDEF"
str.insert(contentsOf:"hello",at:str.startIndex)//helloABCDEF
str.insert(contentsOf:"hello",at:str.index(str.startIndex,
                                           offsetBy:3))
//在母字符串的第三位上插入hello字符串
7.字符串替换
  • 自定义范围替换 | .replaceSubrange(range,with:" ")
var str = "ABCDEF"
let index1 = str.index(str.startIndex, offsetBy: 1)
let index2 = str.index(str.startIndex, offsetBy: 3)
let range = index1...index2  //自定义了需要替换字符串的范围
str.replaceSubrange(range, with: "123")
print(str)
//输出:
//A123EF
  • 已有字符串进行替换 | replacingOccurrences(of: “原字符串”, with: “替换的新字符串”)
var str = "ABCDEF"
var newstr = str.replacingOccurrences(of: "BC", with: "123")
//newstr = "A123DEF"
8.字符串删除
  • 单个字符删除 | .remove(at: String Index)
var str = "ABCDEF"
str.remove(at: str.index(str.startIndex, offsetBy: 2)) //C
print(str)
//输出:
//ABDEF
  • 范围删除 | .removeSubrange(range)
var str = "ABCDEF"
var a = str.index(str.startIndex, offsetBy: 1)  //B
var b = str.index(str.startIndex, offsetBy: 3)  //D
str.removeSubrange(a...b)
print(str)
//输出:
//AEF
9.遍历字符串
  • 简易遍历
for index in str
{
    print(index)
}
/*
A
B
C
D
E
F
*/
  • 精准遍历 通过控制String Index来控制遍历
var str = "ABCDEF"
for index in (0..<str.count)
{
    print(str[str.index(str.startIndex, offsetBy: index)])
}
/*
A
B
C
D
E
F
*/
10.多行文本

通过三个引号括起来 “““ ””” 其中的文本格式会随着编写格式改变

var value = """
                hello
                    world

            """
11.转义字符串 | #“ ”#
var value = #""hello""# //井号加引号中的内容都当作字符串
//"hello"

函数

1.函数定义
//常用定义
func test()
{
    //函数体
}

//具有返回类型
func test2(name:String) -> String
{
    return name
}
print(test2(name:"hello world"))
//hello world

//输出参数可以输入很多个值
func test3(name:String...) //name是个Array<String>类型
{
    for item in name
    {
        print(item)
    }
}
test3(name:"a","b")
//a
//b

//定义参数为元组的函数
func test(name:(n1:String,n2:Int)) -> (String,Int)
{
    var value:(a:String,b:Int)
    value.a = name.n1 + " world"
    value.b = name.n2 + 20
    
    return value
}
var value = test(name: ("hello",10))
print(value)
//("hello world", 30)
2.函数参数
//前面为外部使用名,后面为内部调用名
func test(outname inname:String) 
{
  print(inname)
}
test(outname: "hello")


//用下划线表示外部名忽略(内部名称不能忽略)
func test(_ inname:String) 
{
  print(inname)
}
test("hello") //当外部名忽略时,外部使用函数可直接传值
3.assert函数断言
func test(param:Int)
{
  if(param < 10)
  {
    assert(false,"停止继续运行")//一定要第一个参数为false才能阻止
    //assert断言,阻止函数继续运行,跳出函数
  }
    print("值= " + String(param))
}
 test(param: 5)
//assertion failed: 停止继续运行: file MyPlaygroundText1.playground, line 8
4.guard语句

guard语句跟if语句完全相反,就是不满足判断条件的进入guard语句,满足判断条件的则不进入guard语句,也可以理解成满足条件的else其他部分进入guard语句

func test(param:Int)
{
    guard param < 10 else {
        print("进入guard语句")
        return
    }
    
    print("hello world")
}
test(param: 5)
//hello world
test(param: 15)
//进入guard语句


//可选择绑定guard语句
var a:String? = "swift"
func test1(param:String?)
{
    guard let value = param else 
    //可选择绑定如果param有值,则会赋值给value,然后不进入guard语句
    //如果param没有值,则会进入guard语句
    {
        print("进入guard语句")
        return
    }
    print(value)
}
test1(param: a)
//swift
5.inout关键字
//inout关键字,可以直接改变传入参数的值,相当于传入参数的地址
func test(param: inout Int) //添加一个inout关键字
{
    param = param * 2
    
    print(param)
}

var a = 10
print("传递前a = "+String(a))
test(param: &a) // 传入的时候需要加一个‘&’,相当于传引用,传地址
print("传递后a = "+String(a))
/*
传递前a = 10
20
传递后a = 20
*/
6.函数类型
  • 定义函数类型
var a:() -> void //没有参数,没有返回值的函数类型
var b:(Int,String) -> Void //Int和String参数类型,没有返回值的函数类型
var c:(Bool,Array<Int>) -> String 
//Bool和Array<Int>数组参数类型,String类型返回值
let d:((name1:Int,name2:String)) -> Dictionary<String,String>
//(name1:Int,name2:String)元组参数类型
//Dictionary<String,String>字典类型返回值
  • 函数类型使用

    任何参数类型和返回类型写法都一致,也都可以用匿名函数写

func test1() -> Void  
{
    print("test1()")
}
var a:() -> Void = test1
a()
//test1()

func test2(param1:String,param2:Int) -> String 
{
    return param1 + String(param2)
}
var c:(String,Int) -> String = test2
print(c("hello",10))
//hello10


//匿名函数的使用
var b:() -> Void = { () -> Void in   //in千万不能忘
    print("匿名函数")
}
b()
//匿名函数

var  d:(String,Int) -> String = {(param1:String,param2:Int) -> String in
    return param1 + String(param2)
}
d("swift",20)
//swift20
7.函数类型作为函数参数使用
func test1() -> Void
{
    print("test1()")
}
var a:() -> Void = test1

func test2(param:() -> Void)
{
    param()
}
test2(param: test1) //或者 test2(param:a)
//输出:
//test1()

//具有参数和返回值的函数类型作为函数参数
func test1(param1:String,param2:Int) -> String
{
    return param1 + String(param2)
}
var c:(String,Int) -> String = test1
func test2(param:(String,Int) -> String)
{
    let Value = param("hello",27)
    print(Value)
}
test2(param: test1)
//hello27


//匿名函数作为参数的使用
func test2(param:() -> Void)
{
    param()
}
test2(param:{() -> Void in
    print("匿名函数,没有参数,没有返回值")
})
//匿名函数,没有参数,没有返回值

//有参数和返回值的函数类型作为函数参数
func test2(param:(String,Int) -> String)
{
    let Value = param("hello",27)
    print(Value)
}
test2(param: {(name1:String,name2:Int) -> String in
    return name1+String(name2)
})
//hello27
8.函数作为返回值
func play1(value:Int) -> Int
{
    return value * value
}

func play2(value:Int) -> Int
{
    return value + value
}
//参数为Bool值,返回(Int)->Int函数
func test(param:Bool) -> (Int) -> Int 
{
    return param ? play1 : play2
}
var a = test(param: true) //a的类型是(Int)->Int
print(a(5))
//25
9.内嵌函数
//参数为Bool值,返回(Int)->Int函数
func test(param:Bool) -> (Int) -> Int 
{
    func play1(value:Int) -> Int
	{
   		 return value * value
	}

    func play2(value:Int) -> Int
    {
        return value + value
    }
    
    return param ? play1 : play2
}
var a = test(param: false) //a的类型是(Int)->Int
print(a(8))
//16
10.匿名函数的简写
//()->Void时

//常规写法:
var a:() -> Void = { () -> Void in   //in千万不能忘
    print("匿名函数")
}
a()
//匿名函数

//简易写法:
var b:() -> Void = {
    print("匿名函数的简易写法")
}
b()
//匿名函数的简易写法

//最简易的写法:
var c = {
    print("匿名函数的最简易的写法")
}
c()
//匿名函数的最简易的写法


//匿名函数作为函数参数:
func test(param:() -> Void)
{
    param()
}
//常规写法:
test(param: {() -> Void in
    print("匿名函数作为函数参数的常规写法!")
})
//匿名函数作为函数参数的常规写法!
//简易写法:
test(param: {
    print("匿名函数作为函数参数的简易写法!")
})
//匿名函数作为函数参数的简易写法!
//最简易的写法:
test{print("匿名函数作为函数参数的最简易写法!")}
//匿名函数作为函数参数的最简易写法!


//(Int) -> Void
func test2(param:(Int) -> Void)
{
    param(10)
}
//常规写法:
test2(param: {(value:Int) -> Void in
    print(value)
})
//简易写法:
test2(param: {(value) in  //value时Int类型 自动类型判断
    print(value)
})
//更简易写法:
test2{(value) in
    print(value)
}


//(Int,Int) -> Int
func test2(param:(Int,Int) -> Int)
{
    print(param(10,20))
}
//常规写法:
test2(param: {(item1:Int,item2:Int) -> Int in
    return item1 + item2
})
//简易写法:
test2(param: {(item1,item2) -> Int in
    return item1 + item2
})
//更简易写法:
test2(param: {return $0 + $1})
//最简易的写法:
test2(param: {$0 + $1})

进阶知识

1.结构体
  • 构造结构体
struct Student
{
    var name = "unknow"
    var age = 0
    var score = 0.0
    var ispass = false
    
    static let schoolName = "qinghua" //静态类,可以直接通过结构体调用
    
    init()
    {
        
    }
    
    init(name:String,age:Int,score:Double) { //结构体初始化
        self.name = name
        self.age = age
        self.score = score
        
        if(self.score < 60)
        {
            self.ispass = false
        }
        else
        {
            self.ispass = true
        }
    }
    
    //结构体的get和set方法,一般不建议在结构体中使用get,set
     func getName() -> String {
        return self.name
    }
    func getAge() -> Int {
        return self.age
    }
    func getScore() -> Double {
        return self.score
    }
    func getisPass() -> Bool {
        return self.ispass
    }
    //使用创建函数set方法直接改变self的值,需要添加mutating关键字
    mutating func setScore(score:Double){ 
        self.score = score
        if(self.score < 60)
        {
            self.ispass = false
        }
        else
        {
            self.ispass = true
        }
    }
}
  • 创建结构体实例
var a = Student() //使用的是init(){}初始构造器
var b = Student(name:"晓晓",age:18,score:87.5)
//调用输出,可以直接调用结构体的属性,也可以调用get方法
print("姓名 = " + b.name)
print("年纪 = " + String(b.getAge()))
print("学校 = " + Student.schoolName)  //静态类型:直接调用结构体
/*
姓名 = 晓晓
年纪 = 18
学校 = qinghua
*/

//调用set方法
b.setScore(score: 10)
print(b.score)
//10.0
  • struct初始化器
struct Test
{
    var name:String
    var age:Int
    //结构体可以不斜init初始化器,结构体会自己自动生成一个如下的初始化器
   /* init(name:String,age:Int) { 
        self.name = name
        self.age = age
    }
   */
}

var t = Test(name: "hello", age: 10)
  • 结构体传递 | 是值传递,不是引用传递
struct Test
{
    var age = 10
}
var t1 = Test()
print(t1.age)

var t2 = t1
print(t2.age)
print("--------------")

t2.age = 100
print(t2.age)
print(t1.age)
/*
10
10
--------------
100
10
*/
  • 结构体计算属性
struct Person
{
    private var value = ""
    var name:String
    { //给name属性添加了get,set方法
        set(param)
        {
            value = param + " hello world" //在set赋值的时候进行计算属性
            print("调用了set方法")
        }
        get
        {
            print("调用了get方法")
            return value + " ios"  //在get return的时候进行计算属性
        }
    }
    
    init() {
        
    }
}

var  person = Person()
person.name = "swift"
person.name
print(person.name)
/*
调用了set方法
调用了get方法
调用了get方法
swift hello world ios
*/
  • 结构体的只读属性
struct Person
{
    private var value = "hello world"
    var name:String
    {
        get
        {
            return value
        }
    }
    
    init() {
        
    }
}

var  person = Person()
person.name = "swift" //因为没有set属性 所以会报错
print(person.name) //可以输出hello world,所以具有只读属性
  • 结构体定义初始值
struct Person
{
    private var value = "hello world"
    var name:String
    {
        set  //如果写private set就无法在外部直接改变name值
        	//只能通过结构体使用时的传入数值
        {
            value = newValue  //可以不写参数 用newValue来传递新值
        }
        get
        {
            return value
        }
    }
    
    init(name:String)
    {
        self.name = name
    }
}

var  person = Person(name:"swift") //给入一个“swift”初始值
print(person.name)
  • 属性观察 | 相当于属性监听
struct Person
{
    var name:String = "unknow"
    { //观察属性,就是当属性发生更替时,会进行willSet和didSet
      //但是只获取属性值的时候,并不会进行willSet和didSet
        willSet  //将新值进行传递
        {
         print("willSet - " + newValue)
        }
        didSet  //将旧值进行传递
        {
         print("didSet - " + oldValue)
        }
    }
}
var person = Person()
person.name = "hello"
person.name = "hello"
/*
willSet - hello
didSet - unknow
willSet - hello
didSet - hello
*/
  • 下标语法subscript
struct Person
{
    var array:[String] = ["swift","macos","ios"]
    subscript(index:Int) -> String //下标语法 更多用在在哪个下标处添加什么数据
    {
        set
        {
            array.insert(newValue, at: index)
        }
        get
        {
            return array[index]
        }
    }
}
var person = Person()
person[0] = "hello" //hello=newValue  0=index
print(person[0])
2.类
  • 类的定义和使用
class Student
{
    var name:String = "" //初始值
    var age:Int = -1  //初始值
    var score:Double = -1.0  //初始值
    var ispass:Bool = false  //初始值
    
    static let schoolName = "哈佛大学"
    
    convenience init() //调用自身的init初始化构造器需要添加convenience关键字
    {
        self.init(name: "unknow", age: 0, score: 0.0)
    }
    
    init(name:String,age:Int,score:Double)  //可以有两种初始化方法
    {
        self.name = name
        self.age = age
        isPass(param: score)
    }
    
    private func isPass(param:Double)  //封装了一个更改分数和判断是否通过的函数
    {
        self.score = param
        
        if(self.score < 60)
        {
            self.ispass = false
        }
        else
        {
            self.ispass = true
        }
    }
    public func setScore(score:Double) //更改分数的函数方法
    {
     isPass(param: score)
    }
    public func getName() -> String {
        return self.name
    }
    public func getAge() -> Int {
        return self.age
    }
    public func getScore() -> Double {
        return self.score
    }
    public func getisPass() -> Bool {
        return self.ispass
    }
}

var s1 = Student()
print(s1.getName())
print(s1.getAge())
print(s1.getScore())
print(s1.getisPass())
print("-------------------")
var s2 = Student(name:"小A",age:18,score:61)
print(s2.getName())
print(s2.getAge())
print(s2.getScore())
print(s2.getisPass())
s2.setScore(score: 8.0)
print(s2.getScore())
print(s2.getisPass())
/*
unknow
0
0.0
false
-------------------
小A
18
61.0
true
8.0
false
*/
  • 类实例传递 | 是引用传递 不是值传递
class Student
{
    var name = "hello"
    
}

var s1 = Student()
print(s1.name)

var s2 = s1
print(s1.name)
print(s2.name)

s2.name = "ios"

print("--------------")
print(s1.name)
print(s2.name)
/*
hello
hello
hello
--------------
ios
ios
*/
  • 类实例定义为常量的一些不同
class Student
{
    var name = "hello"
    
}

let s1 = Student()  //实例定义为常量 仍可以改变属性值
print(s1.name)

s1.name = "world"
print(s1.name)
//hello
//world
  • 属性计算 属性观察 下标语法

    类的属性计算,属性观察,下标语法和结构体的功能,使用方法相同

  • 类的继承

class Person
{
    private var name:String
    private var age:Int
    
    init(name:String,age:Int) {
        self.name = name
        self.age = age
    }
    
    public func setName(name:String)
    {
        self.name = name
    }
    public func setAge(age:Int)
    {
        self.age = age
    }
    public func getName() -> String
    {
        return self.name
    }
    public func getAge() -> Int
    {
        return self.age
    }
}

class Student:Person 
//Student是Person的一个子类,继承了Person的一些功能和函数
//在子类定义的一些函数方法,就是在父类上再添加的函数和方法,子类独有
{
    func paly(param:String)
    {
        print(param)
    }
}
var per = Person(name:"person",age:10)
print(per.getName())
print(per.getAge())
print("--------------------")
var stu = Student(name:"stu",age:18)
print(stu.getName())
print(stu.getAge())
/*
person
10
--------------------
stu
18
*/
  • 向下类型转换
var stu:Person = Student(name:"stu",age:18) //Student是属于Person的子类所以可以这么写
print(stu.getName()) //因为Person下有getName方法 所以可以正常运行
print(stu.getAge())
print("--------------------")
var stu:Any = Student(name:"stu",age:18)
print(stu.getName()) //因为Any类型中没有getName方法 所以会报错
print(stu.getAge())
if let s = stu as? Student  //通过可选项类型绑定 进行向下类型转换
  //如果stu属于Student类型 就将Student类型赋值给s
{
    print(s.getName()) //可选项类型绑定后,s就有getName方法
    print(s.getAge())
}
  • 子类重写方法
class Person
{
    var name:String
    var age:Int
    
    init(name:String,age:Int) {
        self.name = name
        self.age = age
    }
    
    public func setName(name:String)
    {
        self.name = name
    }
    public func setAge(age:Int)
    {
        self.age = age
    }
    public func getName() -> String
    {
        return self.name
    }
    public func getAge() -> Int
    {
        return self.age
    }
}

class Student:Person
{
    override var name: String
    {
        set
        {
            super.name = super.name + "- student"
        }
        get
        {
            return super.name
        }
    }
    override init(name: String, age: Int) //重写初始化器
    {
        super.init(name: name, age: age) //先创建一个父类实例,使用super方法名
       
        self.name = name //对子类自己进行初始化
        self.age = age //把父类方法获得的age给到子类的age
        //如果是self.setAge(age:age),则是将父类setAge后的age给到子类age
    }
    
    //或者重写方法,如果Student的实体调用getName则使用重写后的方法
    //取消override var name: String这个变量方法后
    override func getName() -> String
    {
        return super.getName() + "- Student"
    }
    override func setAge(age:Int)
    {
        super.setAge(age:age - 10)
        print("年轻十岁不是梦")
    }
}
var per = Person(name:"小A",age:10)
print(per.name)

var stu = Student(name: "小B", age: 27)
print(stu.name)
/*
小A
小B- student
*/
  • 关于创建父类实例初始化super.init
class Test
{
    var name:String
    var age:String
    required init(name:String,age:String)
    {
       self.age = name //将name和age进行交换
       self.name = age
    }
}

class T:Test
{
    required init(name: String, age: String) {
        super.init(name: name, age: age) //观察这个super.init是具体如何赋值
    }
}

var t = T(name: "name", age: "age")
print(t.name)
print(t.age)
/*
age
name
*/
//结论:创建t实例是,传入的"name"字符串,先给到第14行的name:String变量
//然后由14行name变量传给15行name:name中后面这个name变量
//然后通过15行的name:name传递给父类初始化器中第5行name:String
//然后根据第8行将"name"字符串传递给t的self.age,也就是t的age是"name"字符串
  • 方法重载

若想要两个函数名相等,那一定要有参数不一样,要不是参数名称不一样,或者参数类型不一样,或者返回类型不一样,或者参数顺序不一样,总归需要有参数是不一样的才可以满足

  • final关键字

若不想让其他类继承该类,则在这个类前面加一个final关键字就行;或者父类的方法不想子类重写该方法,在该方法前写一个final关键字就行

  • 属性计算 属性观察 下标语法的继承和重写

属性计算 属性观察 下标语法的继承和类的继承相同,重写只需要在该子类的方法上用override重写即可

  • 多态类型方法调用
class A
{
    var name:String
    
    init(name:String) {
        self.name = name
    }
    
    func printName()
    {
        print("this is A " + name)
    }
}

class B:A
{
    override func printName() {
        print("this is B name = " + name)
    }
    
    func play() //该方法为子类有,但父类没有的方法
    {
        print("this is B play")
    }
}

class C:A
{
    override func printName() {
        print("this is C name = " + name)
    }
    
    func play() //该方法为子类有,但父类没有的方法
    {
        print("this is C play")
    }
}

var s2:A = B(name:"b")  //多态:父类类型的引用指向子类类型的对象    
print(s2.name)
print(type(of: s2))
s2.printName() //s2会在A中找有没有printName方法,如果有则调用B中的printName方法
s2.play() //没有这个方法,因为s2在A中找不到play方法,即使B中有也无法调用
/*
输出:
b
B
this is B name = b
*/

func getObject(param:Int) -> A
{
    if (param > 15)
    {
        return B(name: "小B")
    }
    else
    {
        return C(name: "小C")
    }
}

//1.强制类型转换方法
var obj = getObject(param: 17)
if(obj is B)
{
    var p = obj as! B  //强制类型转换
    p.play()
}
else if(obj is C)
{
    var p = obj as! C  //强制类型转换
    p.play()
}
/*
输出:
this is B play
*/
//2.强制类型转换
if let t1 = obj as? B
{
    t1.play()
}
else if let t1 = obj as? C
{
    t1.play()
}
  • 扩展extension
class A
{
    
}

extension A //在A类上增添其他变量或方法
{
    var name:String{return "hello world"} //get只读类型简写方法

    
    func toString()
    {
        print("this is A toString")
    }
}

var  a = A()

a.toString()
a.name

//也可以对现有的类或结构体进行扩展
extension String
{
    func toString() -> String
    {
        return "长度 = " + String(self.count)
    }
}
  • 泛型
func fun<T>(param:T) -> T  
//T代表一个数据类型,但不明确指定,在<>里确定了什么数据类型,就是泛型
//var array:Array<Int> = [1,2,3] 这也就是一个泛型,只是限定的类型是Int

//这样传递什么数据类型,T就是什么数据类型
{
    return param
}

print(fun(param: "hello"))
print(fun(param: 2))
print(fun(param: 1.4))
print(fun(param: [1,2,3,4]))
/*
hello
2
1.4
[1, 2, 3, 4]
*/
  • protocol协议
class TestClass
{
    
}

protocol Protocol1
//协议里面只需写需要哪些参数类型,具体方法在具体类中写
//协议只规定该协议需要什么类型,以及什么方法
//具体类的方法在实例里都可以写,协议不会限制类的方法编写,只是使不使用的问题
{
    var value1:String {set get}
    
    func play1() -> String 
}

protocol Protocol2
{
    var value2:String {get}
    
    func play2() -> String
}

class Data:TestClass,Protocol1,Protocol2
{
    var value1: String
    let value2: String = "hello"
    init(value1:String)
    {
        self.value1 = value1
    }
    
    func play1() -> String {
        return self.value1
    }
    
    func play2() -> String {
        return self.value2
    }
}

var data = Data(value1: "value1")
print(data.value1)
print(data.value2)
print(data.play1())
print(data.play2())

data.value1 = "value123"
print(data.value1)
  • protocol协议中定义协议泛型
protocol Test
{
    associatedtype D //定义了协议当中的泛型
    func play(param:D) //具体是什么类型,在使用类中进行定义
}

class Student:Test
{
    func play(param:String) //在使用类中定义协议中D的类型
    {
        print(param)
    }
}

var s = Student()
s.play(param: "hello")
  • lazy懒加载(延迟属性)| 系统优化功能
class Data
{
    init()
    {
        print("Data init")
    }
 
    func play()
    {
        print("Data play")
    }
}

class Test
{
     lazy var data:Data = Data() 
    //lazy懒加载,需要用到这个参数时,再对这个参数进行初始化和调用
   
    init()
    {
        print("Test init")
    }
}

var test = Test()
//Test init  只有上面一句的时候,只打印这一句
test.data
//Test init
//Data init  调用到data数据的时候,才会初始化data参数
  • 普通初始化器 和 可失败初始化器
//普通初始化器
class Test
{
    var name:String
    init(name:String)
    {
        self.name = name
    }
}
var t = Test(name:"hello")
print(t.name)
//hello

//可失败初始化器
class Test
{
    var name:String
    init?(name:String) //在init后面加?号
    {
        if (name == "unknow") //然后在初始化器中进行判断
        {
            return nil
        }
        self.name = name
    }
}
var t:Test? = Test(name:"hello") //t为Test类型的可选类型,因为t可能为空,t也可能为Test类型的值
if let p = t
{
    print(p.name)
}
else
{
    print("初始化失败")
}
  • 必要初始化器
class Test
{
    var name:String
    required init(name:String) //required必要初始化器关键字
    {
       self.name = name
    }
}

class T:Test
{
    required init(name: String) 
    //当父类设置了必要初始化器,子类就必须要进行初始化器
    {
        super.init(name: name) 
    }
}

var t = T(name: "name")
print(t.name)
  • 闭包设置初始化属性值
class Test
{
    var name:String = {return "swift"}() //闭包设置初始值,闭包后必须要有一对小括号
    var age:Int =
    {
        var a = 10
        var b = 20
        return a + b
    }() //闭包也可以进行一些属性计算
}

var t = Test()
print(t.name)
print(t.age)
  • ARC工作机制

    对于创建的一个类,没有实例去引用这个类,这个类就会在内存中被销毁,就会不占用内存

  • 反初始化器

class Test
{
    var name:String
    init(name:String)
    {
        self.name = name
    }
    deinit { //反初始化器,当所在的类没有被调用,被内存销毁,则反初始化器被调用
        print("Test被销毁" + self.name)//通常写的是一些对象销毁收尾工作
    }
}
var t1:Test? = Test(name: "hello")
var t2:Test? = t1
var t3:Test? = t1

t1 = nil
t2 = nil
t3 = nil
  • 强引用

    代码中只要对一个类有引用,有使用,那就是对这个类的强引用,这个类就不会被内存销毁

class TestA
{
    var name:String
    var  ref:TestB? = nil
    init(name:String)
    {
        self.name = name
    }
    deinit {
        print("TestA被销毁" + self.name)
    }
}
class TestB
{
    var name:String
    var  ref:TestA? = nil
    init(name:String)
    {
        self.name = name
    }
    deinit {
        print("TestB被销毁" + self.name)
    }
}
//创建testA,testB对象
var testA:TestA? = TestA(name: "A")
var testB:TestB? = TestB(name: "B")

//将testA中的ref指向testB,将testB中的ref指向testA
testA!.ref = testB
testB!.ref = testA

//将互相依赖ref释放
testA!.ref = nil
testB!.ref = nil

//将对象testA,testB释放
testA = nil
testB = nil

//输出:类TestA。TestB因ARC机制被释放
//TestA被销毁A
//TestB被销毁B
  • weak弱引用

    如果类的所有强引用解除,就算有弱引用连接着,但仍会有ARC工作机制,使得该类被销毁,弱引用不会阻止ARC工作机制

class TestA
{
    var name:String
    var  ref:TestB? = nil
    init(name:String)
    {
        self.name = name
    }
    deinit {
        print("TestA被销毁" + self.name)
    }
}
class TestB
{
    var name:String
    weak var  ref:TestA? = nil //因为采用弱引用,所以不影响ARC工作机制
    init(name:String)
    {
        self.name = name
    }
    deinit {
        print("TestB被销毁" + self.name)
    }
}

var testA:TestA? = TestA(name: "A")
var testB:TestB? = TestB(name: "B")

testA!.ref = testB
testB!.ref = testA

testA = nil //因为弱引用,所以即使存在testB!.ref = testA也没有用

//输出:
TestA被销毁A

逻辑思维导图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YmB4z2Z2-1648816854793)(C:\Users\22166\AppData\Roaming\Typora\typora-user-images\image-20211210202020902.png)]

  • 无主引用unowned

    weak弱引用与unowned无主引用类似,不同点是unowned是永远有值的,weak可以声明可选型,很多时候我们不想声明一个可选型,可选性代表着风险,此时就可以将属性声明称unowned

//当TestB类似于一个无主引用类
class TestA
{
    var name:String
    var  ref:TestB? = nil
    init(name:String)
    {
        self.name = name
    }
    deinit {
        print("TestA被销毁" + self.name)
    }
}
class TestB
{
    var name:String
    var  ref:TestA
    init(name:String,ref:TestA)
    {
        self.ref = ref
        self.name = name
    }
    deinit {
        print("TestB被销毁" + self.name)
    }
}

var testA:TestA? = TestA(name: "A")

testA!.ref = TestB(name: "B", ref: testA!)
testA?.ref = nil //当testA指向TestB的ref断开后,TestB就被内存释放
			//于是TestB指向TestA的ref自动断开,所以此时TestB被销毁
testA = nil  //此时testA指向TestA的强引用断开,TestA被内存释放
//TestB被销毁B
//TestA被销毁A

//unowned的使用 无主引用类似于弱引用,不会影响ARC工作机制
class TestA
{
    var name:String
    var  ref:TestB? = nil
    init(name:String)
    {
        self.name = name
    }
    deinit {
        print("TestA被销毁" + self.name)
    }
}
class TestB
{
    var name:String
    unowned var  ref:TestA //TestB指向TestA的ref是无主引用
    init(name:String,ref:TestA)
    {
        self.ref = ref
        self.name = name
    }
    deinit {
        print("TestB被销毁" + self.name)
    }
}

var testA:TestA? = TestA(name: "A")

testA!.ref = TestB(name: "B", ref: testA!)

testA = nil //因为此时testA指向TestA的强引用解除,所以TestA直接释放
		//于是TestA与TestB互指的ref因TestA释放,依次失效并释放内存
//TestA被销毁A 
//TestB被销毁B
  • 闭包循环引用

    闭包的功能:保存上下文,防止被销毁

class TestA
{
    var name:String
    lazy var data:() -> Void = {() -> Void in 
//因为调用data的时候,可能初始化还未完成
//所以使用lazy等确定初始化完成后,才会执行data函数
        print("姓名 = " + self.name)
    }
    init(name:String)
    {
        self.name = name
    }
    deinit {
        print("TestA被销毁" + self.name)
    }
}

var t:TestA? = TestA(name: "hello")
t!.data()
t = nil //可以发现,TestA并没有被销毁
//原因是data()中的self是对TestA的强引用
//所以出现了TestA指向data()闭包,data()闭包指向TestA的闭包循环使用
//姓名 = hello
  • 定义捕获列表
//通过捕获列表,来定义指向TestA类的指向类型,来实现最终可以对TestA类的内存释放
class TestA
{
    var name:String
    lazy var data:() -> Void = {[unowned self]() -> Void in 
//在闭包前用[]定义捕获列表的类型,可以是unowned,weak(需要加!号给肯定)
        print("姓名 = " + self.name)
    }
    init(name:String)
    {
        self.name = name
    }
    deinit {
        print("TestA被销毁" + self.name)
    }
}

var t:TestA? = TestA(name: "hello")
t!.data()
t = nil
//姓名 = hello
//TestA被销毁hello
  • 尾随闭包
//双参数写法
//正常写法:
func play1(param1:String,param2:(String) -> Void)
{
    param2(param1 + " - Swift")
}
play1(param1: "hello", param2: {(data:String)-> Void in
    print(data)
})
//尾随闭包写法:
play1(param1: "world") { (data:String) -> Void in
    print(data)
}
//hello - Swift
//world - Swift

//单参数类型
//正常写法
func play2(param:(String) -> String)
{
    var value = param("Swift")
    print("返回值 =  " + value)
}
play2(param: {(data:String) -> String in
    return data + " - ios"
})
//尾随闭包写法:
play2 { (data) -> String in
    return data + " - macos"
}
//返回值 =  Swift - ios
//返回值 =  Swift - macos
3.错误捕获和处理
enum TestError:String,Error
{
    case error1 = "错误1"
    case error2 = "错误2"
}
func play(param:Int) throws
{
    if (param < 0)
    {
        throw TestError.error1
    }
    else if(param >= 0 && param < 10)
    {
        throw TestError.error2
    }
    
    print("正常执行")
}

//do catch捕获错误
do {
    try play(param: -19)  //可能发生错误的语句执行
}
catch TestError.error1  //捕获错误情况1,可以有很多个catch
{
    print(TestError.error1.rawValue)
}
catch TestError.error2	//捕获错误情况2
{
    print(TestError.error2.rawValue)
}
defer	//不管结果如何都会执行的语句
{
    print("defer")
}
//错误1
//defer

//处理异常的另一种解决办法,使用可选类型
enum TestError:String,Error
{
    case error1 = "错误1"
    case error2 = "错误2"
}
func play(param:Int) throws -> String
{
    if (param < 0)
    {
        throw TestError.error1
    }
    else if(param >= 0 && param < 10)
    {
        throw TestError.error2
    }
    
    print("正常执行")
    return "hello world"
}

var value = try? play(param: 100)
print(value != nil ? value! : "unknow")
//或print(value ?? "unknow")
//正常执行
//hello world
4.泛型类型限定
class Data
{
    var name:String
    init(name:String)
    {
        self.name = name
    }
}

func play<T:Data>(param:T) //使用泛型,但是泛型限定成Data,泛型类型限定
{
    print(param.name)
}
play(param: Data(name: "hello"))
5.协议关联类型限定
class Data
{
    var name:String
    init(name:String)
    {
        self.name = name
    }
}

protocol Test
{
    associatedtype D:Data //协议关联类型,也可以理解成协议泛型限定
    func play(param:D)
}

class Student:Test
{
    func play(param:Data)
    {
        print(param.name)
    }
}

var s = Student()
s.play(param:Data(name: "swift"))
//swift
6.访问权限
  • private:private访问级别所修饰的属性或者方法只能在当前类里访问
  • fileprivate:fileprivate访问级别所修饰的属性或者方法在当前的Swift源文件里可以访问
  • internal(默认访问级别,internal修饰符可写可不写):internal访问级别所修饰的属性或者方法在源代码所在的整个模块都可以访问。如果是框架或者库代码,则在整个框架内部都可以访问,框架由外部代码所引用时,则不可以访问。如果是App代码,也是在整个App内部都可以访问
  • pubic:可以被任何人访问,但其他module中不可以被overrride和继承,而在modile内可以被override和继承
  • open:可以被任何人使用,包括override和继承
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

淡酒交魂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值