可选变量:
一. 在Swift中可选类型(Optionals),用 " ? " 号表示, 用于处理值缺失的情况. 表示"该处有一个值, 切它等于X", 或者表示"该处没有值"
二. 可选类型是一个包含两种情况的枚举值: None 和 Some , 用来表示可能有值(Some) 或可能没有值(None)
2.1 nil 就是Optional.None, 当你声明一个可选变量, 或者可选属性的时候, 没有提供初始化值, 它的值默认为 nil
2.2 非nil 就是Optional.Some
三. 任何类型都可以明确的声明为可选类型, 当声明一个可选类型的时候, 要确保用括号给" ? " 操作符一个合适的范围. 例如: 声明可选整数数组, 格式为: (Int[])?, 如果写成"Int[]?", 就会报错
定义一个可选类型: 两种方式
var Optional_1:Int? //注意: 在数据类型和" ? "号之间没有空格
var Optional_2:Optional<Int> // 这里表明关键字可选类型
四: " ! " 号, 用来表示强制解析, 如果可选类型实例包含一个值, 可以用" ! "号来访问这个值.
注意: 如果可选类型在没有赋值的情况下, 进行强制解析, 会导致崩溃
var intNumber:Int? = 8
var result1 = intNumber // 打印结果Optional(8)
var result2 = intNumber! // 打印结果直接是 8
print(result1, result2
五. 自动解析(隐式解析)
5.1 你可以在声明可选变量时, 使用 " ! " 号来替换 " ? ", 这样可选变量在使用时, 就不需要在加一个 " ! "进行解析了, 它会自动解析.
5.2 隐式解析可选类型和可选类型一样, 都是有值和没有值(nil)两种结果.
5.3 区别在于赋值/取值时, 隐式解析可选类型不需要再强制解析
5.4 注意: 隐式解析可选类型的变量没有值时, 程序一样会崩溃
var IntNumberOne:Int! = 10
print(IntNumberOne)
六. 可选绑定
6.1 可选绑定: 用来判断, 可选类型是否包含值, 如果包含就把值赋给一个临时常量/临时变量
6.2:可选绑定可以用在 if 和 while 语句中来对可选类型的值进行判断, 并把他赋给一个常量或者变量
6.3 如果你不确定类型是否有值, 用可选绑定, 不需要对可选类型强制解析
var intNumberTow:Int?
if var intNumberThree = intNumberTow
{
print("可选类型有值 = ",intNumberThree)
}else
{
print("可选类型没有值")
}```
--------------------
结构体:
-------
>一: 与 C 和 OC 不同的是:
1.1: 结构体不需要包含实现文件和接口文件
1.2: 结构体允许我们创建一个单一文件, 且系统会自动生成该结构体面向其他代码的外部接口
> 二: 结构体总是通过被复制的方式在代码中传递, 因此, 该结构体原本的值是不可修改的
>三: 结构体的应用
3.1: 在代码中可以使用结构体定义你的自定义类型数据
3.2: 按照通用的准则, 当符合一条或者多条以下条件时候, 请考虑构建结构体
>> 3.2.1: 结构体的主要目的是用来封装少量相关简单数据
3.2.2: 有足够的理由预计一个结构体实例在赋值或者传递时, 封装的数据将会被拷贝而不是应用
3.2.3: 任何结构体中存储的值类型属性, 也将会被拷贝, 而不是被应用
3.2.4: 结构体不需要继承另一个已经存在类型的属性或者行为
> 四: 举例:
4.1: 几何形状大小, 封装一个 width 属性和 height 属性,两者均为 Double 类型
4.2: 一定范围的路径, 封装一个 Start 属性和 Length 属性, 两者均为 Int 类型
4.3: 三维坐标系内的一点, X, Y, Z, 三者均为 Double 类型
``` code
// 声明一个结构体
struct piontOf3D
{
// 声明结构体变量的属性 (存储属性)
var X : Double
var Y : Double
var Z : Double
}
// 创建结构体实例
var D3:piontOf3D = piontOf3D.init(X: 1, Y: 1, Z: 1)
// 声明一个结构体
struct Rect
{
var ponit : (x : Int , y : Int) = (0 , 0)
var size :(w :Int , h : Int ) = (0 , 0)
// 成员方法
func getSize()
{
print(size)
}
// 类方法 : 用 Static 修饰
static func sayHellon ()
{
print("你好, 我是结构体类方法")
}
}
var rect2 : Rect = Rect.init(ponit: (x: 10, y: 10), size: (w: 20, h: 20))
// 调用成员方法
rect2.getSize()
// 调用类方法 (用结构体名调用)
Rect.sayHellon()
类:
一 : swift 中类和结构体有很多共同点
1.1: 定义属性, 用于存储值
1.2: 定义方法, 用于提供功能
1.3: 定义构造器, 用于提供初始化值
1.4: 遵循协议, 用来对某个类提供标准功能
1.5: 通过扩展, 用来增加默认实现的功能
二 : 与结构体 相比又有其他附加功能
2.1: 继承允许一个类继承另一个类的特征
2.2: 类型转换允许在运行时检查和解释一个类实例的类型
2.3: 引用计数: 允许对一个类多次引用
三 : 存储属性: 存储属性就是类或者结构体里定义的变量 (或者变量) (OC 中的一个类中引用另一个类)
3.1: 存储属性可以是变量存储属性(var 修饰), 也可以是常量存储属性(let 修饰)
3.2: 可以在定义存储属性的时候指定默认值
3.3: 也可以在构造过程中设置或者修改存储属性的值
四: 计算属性 不直接存储值, 而是提供一个 getter 和一个可选的 setter, 来间接获取和设置其他属性常量或者变量的值
// 声明一个类
class Car
{
// 声明存储属性
var kind : String?
// 声明计算属性
var number : Int
{
get
{
return 10
}
set
{
print(newValue) // 相当于这个传入参数
}
}
// 构造方法
init (kind : String)
{
self.kind = kind
}
}
// 创建实例对象
var volvo = Car (kind: "BMW")
// 访问
print(volvo.kind,volvo.number)
// 声明类属性
class Docter
{
// 类属性只能类方法调用
static var name : String?
// 声明类方法 static 修饰 子类不可以重写 类方法中只能使用类属性 不能使用对象属性
static func sayBybeBybe ()
{
print(name)
}
// 子类可以重写的类方法
class func sayNoByble()
{
print(name)
}
// 对象方法
func sayGoodBybe()
{
print("我就是实例方法")
}
var age : Int?
var Number : Int{
get
{
return age!
}
set (value)// 这种写法表示在调用的 Number的 set 方法时, 传过来参数赋给 value
{
age = value // 切记: set\get 方法中不能使用"self.名称 ", 会造成递归
}
}
// 构造方法中不能使用类属性
}
var DaPeng : Docter = Docter()
DaPeng.sayGoodBybe()
// 继承
class nurse: Docter
{
override class func sayNoByble()
{
print("重写了父类的方法, 使用 override 修饰")
}
}
值类型与引用类型:
一:值类型:
该类型的每一个实例持有数据的副本, 并且该副本对于每一个实例来说都是唯一的一份, 比如结构体, 枚举, 元组都是值类类型
二: 值类型使用场景
2.1: 当使用"==" 运算符比较实例数据的时候
2.2: 当想单独赋值一份实例数据的时候
2.3: 在多线程环境下操作数据的时候
三: 引用类型(如同 OC 中的指针指向同一内存)
该类型的实例共享数据唯一的一份副本, 比如说(class)类就是引用类型
值类型:
struct StructObject
{
var data : Int = 1
}
var value_1 : StructObject = StructObject()
// 将 value_1 的值赋给 value2, 就是一个拷贝的过程
var value_2 = value_1
print(value_2)
// 这里只能改变 value_1 的值 不能改变 value_2 的值 这些都是值类型
value_1.data = 0
print("值引用都是副本\(value_1.data)************\(value_2.data)")
引用类型:
class ClassObjecct
{
var data : Int = -1
}
var cob_1 = ClassObjecct()
// 将 cob_1的值赋给 cob_2, 就是引用的过程
var cob_2 = cob_1
cob_1.data = 4
print("引用类型, 改一个全部改了",cob_1.data, cob_2.data)
var cob_3 = ClassObjecct()
print(cob_3.data)
协议:
- 1: 协议定义了一个蓝图,规定了用来实现某一特定工作或者功能所必需的方法和属性
- 2: 类, 结构体, 枚举都可以遵守协议, 并提供具体实现来完成协议定义的方法和功能
- 3: 任意能够满足协议要求的类型, 被称为(conform)这个协议
- 4: 使用"@objc"修饰的协议, 其中的方法, 可以声明成可选实现(用 optional 修饰)
注意1:
- 使用@objc修饰的协议表示 OC 的协议
- @objc修饰的协议
不可用在结构体里面遵守
- 使用@objc修饰的协议里可以声明可选实现的函数(用
optional
修饰函数) - 在实现这个函数的时候,在函数前面要加
@objc
修饰
注意2:
- 使用
mutating修饰
的函数可以在结构体里面修改结构体的属性
- 协议里面使用mutating修饰的函数,在遵守协议的时候可以不使用mutating修饰,在类里没有影响,在结构体力面,就不能修改属性的值了.
- 但是如果实现协议里没有mutating修饰的函数的时候,却用了mutating修饰,结果是在结构体重新声明了一个函数,此函数和协议无关系
// 带有可选实现函数的协议
@objc protocol MenDelegate
{
func cook()
func wash()
optional func hitJJ()
}
// 必须实现的 函数协议
protocol DividDelegate
{
func lookKid()
}```
- 要遵循某个协议, 如果类在遵循协议的同时拥有父类, 应该将父类名放在协议之前, 用逗号隔开
```code
# doc 继承于 Docter类 遵守 MenDelegate,DividDelegate协议
class doc: Docter,MenDelegate,DividDelegate
{
#实现协议方法
@objc func cook() {
print("做饭的女人")
}
@objc func wash() {
print("洗衣服的女人")
}
func lookKid() {
print("照顾孩子")
}
}
// 创建实例 并调用类的实例方法
var doc1 : doc = doc()
doc1.cook()
doc1.lookKid()
doc1.wash()
延展:
1: Extension + 类名或者结构体名 (可以给一个类或者结构体扩展方法)
2: Extension 可以多次对一个类进行扩展, 也可以给一个类扩展协议方法
3: 扩展就是向一个已有的类, 结构体, 枚举添加新功能
4: 扩展可以对一个类型添加新的功能, 但是不能重写已有的方法
// 给 doc 类扩展方法
extension doc
{
// 实例方法
func say()
{
print("i-LOVE-u")
}
// 扩展类方法
class func eat()
{
print("i-WANT-u")
}
}
doc.eat()
doc1.say()
// 扩展一个 类 遵循协议中的方法
@objc protocol Magic
{
func magic ()
}
extension doc : Magic
{
@objc func magic()
{
print("我会变魔术")
}
}
var docc : doc = doc()
docc.magic()
// 给协议新添加方法并实现 遵循这个协议的实例可以调用这个方法
// 扩展一个 类遵循协议 中的方法
extension MenDelegate
{
func magic()
{
print("12345678")
}
}
class stu : MenDelegate
{
@objc func wash() {
}
@objc func cook() {
}
}
var sutt : stu = stu()
sutt.magic()
闭包:
1: 闭包: 是自包含的函数代码块, 可以再代码中被传递, 使用
2: Swift 中的闭包和 OC 中的 Block 以及其他语言中的匿名函数类似
3: 闭包可以捕获和存储其所在上下文中任意的常量和变量 (闭包并包裹着这些常量和变量)
4: Swift 会帮你管理在捕获过程中涉及到的内存操作
5: 格式: {(参数名 : 类型) ->返回值类型 in 需要执行的代码 }
6: let backString = {(name : String) -> String in return name }
7: 闭包的函数体部分由关键字 in 引入, 该关键字表示闭包的参数和返回值类型定义已经完成, 闭包函数体即将开始
代码举例:
// 求两个数的最大值
// (a : Int , b : Int ) -> Int是表示maxReult的函数类型
var maxReult : ((a : Int , b : Int ) -> Int )
// 第一种方式
maxReult = {(a : Int , b : Int ) -> Int in
return a > b ? a : b
}
// 第二种方式
maxReult = { a , b -> Int in return a > b ? a : b }
// 第三种方式
maxReult = { a , b in a > b ? a : b }
// 第四种方式 (官方推荐)
maxReult = {( a , b) -> Int in return a > b ? a : b }
// 第五种方式
maxReult = { $0 > $1 ? $0 : $1 }
print(maxReult(a: 3,b: 5))