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