1> 可选类型(?)和强制解包(!)
在swift中,可选类型(?) 其根源是一个 枚举型,里面有 None 和 Some 两种类型。其实所谓的 nil 就是 Optional.None , 非 nil 就是 Optional.Some.
可选类型是的数据如果不进行解包的话,它是一个 Optional 类型的数据,如果我们想要使用原来类型的数据,必须进行解包
2> 可选绑定
可选类型分为有值和没值,如果可选类型的变量没值时对其强制解包,程序就会崩溃,所以,强制解包是非常危险的
如果不确定可选类型变量是否有值时,用可选绑定,不需要对可选类型强制解包
3> 隐式解析可选类型(!)
隐式解析可选类型和可选类型一样,都是 有值 和 没值(nil) 两种结果,区别是赋值时,隐式解析可选类型不需要强制解包。
1 //MARK: - ?和 ! 的区别 2 // ? 代表可选类型,其实质是一个枚举类型,里边有None和some两种类型,其实所谓的nil值相当于Optional.None,如果有值相当于Optional.Some 3 // !有值,没值(nil) 4 5 // !强制解包 6 7 var num : Int? = 8 8 // 如果对没值(nil)的变量进行强制解包的情况下会造成崩溃 9 var num1 = num! 10 print(num1) 11 12 // 可选绑定,不用强制解包 13 if var num2 = num { 14 print(num2) 15 } 16 17 // !隐式解析可选类型:有值,没值(nil) 18 19 // 如果强制解析没值的变量也会造成崩溃 20 var intNum : Int! = 9 21 var intNum1 = intNum 22 print(intNum1) 23 24 // 可选绑定 25 if var intNum2 = intNum { 26 print(intNum2) 27 }
2.结构体
1> 概述
Swift的结构体对比OC来说,可以添加初始化方法、可以遵守代理协议等
声明一个结构体的格式:
struct + 结构体的名字 + {
声明成员变量等
}
2> 声明一个结构体代码
1 //MARK: - 结构体 2 // 声明一个结构体 3 struct Rect { 4 // 声明结构体变量的属性(存储属性) 5 var x:Float 6 var y:Float 7 var Float 8 var height:Float 9 //声明结构体属性,要使用static 10 static var description:String? 11 // 声明一个计算属性(是用来专门修改结构体变量属性的setter方法,和getter方法,其自身并没有存储功能) 12 var centerX:Float { 13 //set方法 14 set{ 15 x = newValue 16 } 17 //get方法(必须得有) 18 get{ 19 return x / 2 20 } 21 } 22 var centerY:Float { 23 //get方法 24 get{ 25 return y / 2 26 } 27 } 28 29 // 结构体中还可以声明方法 30 // 声明一个结构体变量方法(相当于OC中的实例方法) 31 func frameInfor(){ 32 print("X:(x),Y:(y),(width),height:(height)") 33 } 34 // 声明一个结构体方法(相当于OC中的类方法),static修饰 35 static func infor(){ 36 print("这是结构体方法") 37 } 38 39 } 40 41 //根据结构体去定义一个结构体变量 42 var frame = Rect(x: 10, y: 10, 100, height: 100) 43 //访问结构体变量中的属性 44 // 注意:结构体变量的属性类型可以使用let去修饰,只不过访问的时候不能进行修改 45 frame.x = 20 46 print(frame.x) 47 48 //如何访问结构体属性 49 Rect.description = "我是结构体属性" 50 print(Rect.description!) 51 52 //怎么访问计算属性 53 frame.centerX = 100 // 这句话相当于在调用centerX的setter方法 54 let value = frame.centerX // 这句话相当于在调用centerX的getter方法 55 print(value) 56 57 // 调用结构体变量方法 ******** 用变量名 58 frame.frameInfor() 59 // 调用结构体方法 ******** 用结构体名 60 Rect.infor()
3.类
1> 概述
类是人们构建代码所用的一种通用且灵活的构造体。我们可以使用与结构体完全相同的语法规则来为类定义属性(常量、变量)和添加方法。
我们通过关键字class来定义类,并在一对大括号中定义它们的具体内容:
class ClassName {
类的内部细节
}
2> 声明一个父类和子类的代码
1 //MARK: - 类(class) 2 class Person { 3 var name : String? 4 var age : Int? 5 // 构造初始化方法 6 init(name:String,age:Int){ 7 self.name = name 8 self.age = age 9 } 10 // 自定义初始化方式 11 init(name:String) { 12 self.name = name 13 } 14 // 声明类属性 15 static var introduce:String? 16 // 声明计算属性 17 var value:Int { 18 // set方法 19 set(a) { 20 age = a // 在写计算属性的时候一定不能出现self. 否则或造成死循环 21 } 22 get { 23 return age! 24 } 25 } 26 // 声明类方法 27 // 在类方法前边加上static修饰【虽然是一个类方法,但是该方法在子类中不能进行重写】 28 static func sayHi() { 29 print(introduce!) // 注意:在类方法中只能使用类属性,不能使用对象属性 30 } 31 // 在类方法前边加上class修饰【他是一个类方法,可以被子类重写】 32 class func sayHa() { 33 print(introduce!) 34 } 35 // 声明一个对象(实例)方法 36 func sayHe() { 37 print("hello iam shilipai") 38 } 39 40 41 } 42 43 // 创建对象【此时应该注意和OC区分开,实例对象,:后边跟的是类】(注意:要初始化对象一定要写初始化构造的方法) 44 var person1:Person = Person(name: "MBBoy", age: 38) 45 // 访问类中的属性 (对象属性) 46 print(person1.name!) 47 48 // 访问类属性 49 Person.introduce = "我是XXXXX" 50 51 // 访问计算属性 52 person1.value = 28 53 print(person1.value) 54 55 // 访问类方法 56 Person.sayHi() 57 Person.sayHa() 58 // 访问实例方法 59 person1.sayHe() 60 61 62 // 定义一个子类student,继承Person 63 // 在swift中不支持多继承 64 65 class Student:Person { 66 // 重写父类的方法 67 // 重写父类中的类方法 68 override class func sayHa() { 69 print("重写类的方法") 70 } 71 // 重写父类中的实例方法 72 override func sayHe() { 73 print("重写实例的方法") 74 } 75 } 76 77 // 初始化student对象 78 var student = Student(name: "小李", age: 18) 79 80 Student.sayHa() 81 student.sayHe()
4. 值类型和引用值类型的区别
值类型
-
该类型的每个实例持有数据的副本,并且该副本对于每个实例来说是独一无二的一份,比如结构体(struct)、枚举(enum)、元组(tuple)都是值类型
-
值传递只是单纯的将数据拷贝一份,赋值给一个同类型的变量,两个变量互不影响,一个值发生改变,另一个不会发生任何变化
引用值类型
-
该类型的实例共享数据唯一的一份副本(在native层面说的话,就是该类型的每个实例都指向内存中的同一个地址),比如类(class)就是引用类型。
- 值传递是将一个变量的地址赋值给另一个变量,当一个值发生改变,两个值同时改变
1 struct animal { // 值类型 2 var name:String? 3 var age:Int? 4 5 init(name:String, age:Int) { 6 self.name = name 7 self.age = age 8 } 9 } 10 11 var dog = animal(name: "贝贝", age: 3) 12 var dog1 = dog // 此时将dog的数据拷给dog1 13 dog.name = "欢欢" 14 15 print("dog.name:(dog.name!), dog1.name:(dog1.name!)") 16 17 // 引用值类型 18 class animal { 19 var name:String? 20 var age:Int? 21 22 init(name:String, age:Int) { 23 self.name = name 24 self.age = age 25 } 26 } 27 28 var dog = animal(name: "贝贝", age: 3) 29 var dog1 = dog // 此时将dog的数据拷给dog1 30 dog.name = "欢欢" 31 32 print("dog.name:(dog.name!), dog1.name:(dog1.name!)")
值类型与引用类型使用情形
- 使用值类型的情形:
使用 == 运算符比较实例数据的时候。
你想单独复制一份实例数据的时候。
当在多线程环境下操作数据的时候。
- 使用引用类型(比如class)的情形:
当使用 === 运算符判断两个对象是否引用同一个对象实例的时候。
当上下文需要创建一个共享的、可变的对象时。
5.协议
1> 概述
-
协议定义了一个蓝图,规定了用来实现某一特定工作或者功能所必需的方法和属性
-
类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能
-
任意能够满足协议要求的类型被称为遵循(conform)这个协议
2> 声明协议
- @objc 修饰的协议,其中的方法可以声明成可选实现(使用optional修饰)
- 声明一个所有函数都必须实现的协议。
3> 遵守协议
类遵守协议,直接写在本类名后面的冒号的后面,使用 "," 号分隔
1 //MARK: - 协议(protocol) 2 // 当swift中声明协议的时候,协议里有可选方法的时候需要使用 @objc 关键字修饰 3 @objc protocol MarryDelegate { 4 func cook() // 做饭 5 func wash() // 洗衣服 6 optional func hitDouDou() // 打豆豆 7 } 8 9 protocol DivorceDelegate { 10 func divisedMoney() // 分割财产 11 } 12 13 // 如果一个类要遵循协议的时候如果这个类有父类,要在冒号后先写父类,然后写要遵循的所有协议,用逗号隔开 14 class Man: Person,MarryDelegate,DivorceDelegate { 15 @objc func cook() { 16 print("还好去新东方学了") 17 } 18 @objc func wash() { 19 print("搓衣板派上用场了") 20 } 21 func divisedMoney() { 22 print("分财产") 23 } 24 } 25 26 // 创建一个男人 27 let man = Man(name: "陈世美", age: 22) 28 man.cook() 29 man.wash() 30 man.divisedMoney()
6.扩展(Extension)
1> 概述
extension + 类名(结构体名字)可以对一个类和结构体扩展方法,类似于 OC 的Category 类目
extension 可以多次对一个类进行扩展,也可以给一个类扩展协议方法
2> 使用Extension给类扩充一个方法
3> 给类扩展实现协议
1 //MARK: - 扩展(Extension) 2 //扩展协议中的相关方法 3 extension Man { 4 @objc func hitDouDou() { 5 print("打豆豆") 6 } 7 } 8 man.hitDouDou() 9 10 // 扩展还可以扩展类的方法(给某个类添加方法,类似于OC中的category类目)以及对象方法 11 extension Man { 12 // 扩展一个对象方法 13 func sing() { 14 print("苍茫的天涯是我的爱") 15 } 16 // 扩展一个类方法 17 class func sleep() { 18 print("早点睡") 19 } 20 } 21 man.sing() 22 Man.sleep()
7.闭包
1> 概述
-
闭包是自包含的函数代码块,可以在代码中被传递和使用。 Swift 中的闭包与 C 和 Objective-C 中的 代码块(block)以及其他一些编程语言中的 匿名函数 比较相似。
-
闭包可以捕获和存储其所在上下文中任意常量和变量的引用。 这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。。
2> 语法形式
{
(参数)-> 返回值类型 in
执行语句
}
3> 闭包的使用(五种方式)
1 //MARK: - 闭包 2 // 求两个数的最大值 3 /* 4 在OC中使用Block实现 5 int(^myBlock)(int num1,int num2) = ^int(int num1,int num2) { 6 return num1 > num2 ? num1 : num2; 7 } 8 */ 9 // 使用闭包 10 // 最内括号是参数和类型,箭头 指向的是返回值类型 11 var myBlock : ((num1:Int, num2:Int)->Int) 12 // 第一种使用方式 13 myBlock = { 14 (num1:Int,num2:Int)->Int in // 切记不能忘记in 15 return num1 > num2 ? num1 :num2 16 } 17 18 // 第二种方式 19 myBlock = { 20 num1,num2 in 21 return num1 > num2 ? num1 : num2 22 } 23 24 // 第三种方式 25 myBlock = { 26 num1,num2 in 27 num1 > num2 ? num1 : num2 28 } 29 30 // 第四种方式 31 myBlock = { 32 $0 > $1 ? $0 : $1 33 } 34 35 // 第五种方式 36 myBlock = { 37 (num1,num2)->Int in 38 return num1 > num2 ? num1 :num2 39 } 40 41 let max = myBlock(num1: 88, num2: 66) 42 print(max)
注意:在class类中声明变量 最好立刻初始化 或 定义为可选变量,不然该类必须重写初始化方法