一、Swift 构建对象
对于 Objective-C
分为两步 alloc 分配内存 init 初始化 [[class alloc]init]
对于Swift
Swift 可以通过更简单的语法创建一个对象 Class()
下面创建一个简单的Swift 类分析一下
class Text {
var age:Int = 18
var name = "text"
let s: String?
init(_ s: String) {
self.s = s
//var mmm = Text("1111111111111111111")
}
}
var t = Text("sss")
sil分析
通过sil文件分析一下可以更容易理解Swift的这个语法
以下是编译过后截图
刚刚的代码编译好之后大概是这个样子
以上发现关键字 @_hasStorage @_hasInitialValue 代表的是 存储属性 和 有默认值的意思有时间可以了解下
根据sil文件自动的注释看到 Text Class 类型的 t 指针 编译成了 "@s4main1tAA4TextCv" 代表 t
看下函数调用, 实例化 t 之前也是先调用了 alloc_global 方法 并传入了 Text 类型先分配 (t 指针的)内存 (alloc_stacck)
特别说一下:
往下看有一个方法是创建 age 属性的 , 特别提到是因为可发现 Swift 中Int 是 struct 这很重要,例如以后使用的时候会发现一些问题 Int("1.1")会失败,直接去结构体中会发现只能传入整形的字符串,否则返回的会是nil,这时候可能需要使用 Float 、 Double ..转化,当然直接点击Int类型进去也可以看见struct Int 一些特性
再往下看 会发现alloc_ 之后会调用 Text 的allocating_init() 方法
把 %10 和 %4 参数传入,最后把返回的地址赋给%3
allocating_inti 的具体实现:
sil 命令文档:https://github.com/apple/swift/blob/main/docs/SIL.rst
以上可看出来其实Swift也是有alloc init 隐式调用的逻辑的
Swift alloc 的源码,有兴趣可以去看一下
通过以上可以发现Swift和objective 构建class对象流程逻辑上没有本质上区别都是先malloc 再 init
HeapObject
不同于ObjectiveC 在内存中存储对象的结构是objc_object ,Swift 对象存储的结构是HeapObject结构,不过也不用过多担心,两个结构内容还是比较统一的
HeapObject 再往里面点
最后会发现有挺长的一个继承链,把这个继承链内容整理起来就是:
保证了和OC混编的时候也可以互相调用
相比于objc_class ,HeapObject为什么这么多继承链呢?,因为HeapObject kind属性不止针对Class类型,struct、enum、Optional...
refCount
也是一个类对象,存储了引用计数、强应用和无主引用、弱引用
二、声明属性
1、存储属性,let 常量、var变量(let声明属性就是只生成get方法不生成set方法)
2、计算属性,就是set、get方法
3、属性观察者,willSet、didSet(就是在赋值前后调用这两个方法没有啥玄学(addObserve不在此处使用))
4、lazy 延迟存储属性
lazy var t:String = "ssss"
lazy关键字修饰必须有默认值
只有第一次访问的时候才被赋值
不保证线程安全
虽然有默认的值内容,但是编译完成之后默认是实际是nil,等到第一次get或者set的时候才有值
5、类型属性
lazy不能保证线程安全,类型属性可以
类型属性是类属性,也就是说类属性跟类实例没有关系,保证内存中只有一根
用 static来声明
static let ashare = Text()
但是实际上和OC声明单例是一个原理,都是调用 GCD 的dispatch_once,所以在Swift也用这种方法声明单例(set方法并不是线程安全的)
6、可选值
感叹号、问号标记
三、结构体
Swift结构体在使用上与Class类似。例如:
Struct Text1{
var title = ""
var 1:String
func pringtTitle() {
print(title)
}
}
var s = Text1()
那Struct和Class的区别在于,结构体属性不需要必须有值,结构体是值类型类是引用类型,是的其他的没有太大的区别,结构体也可以遵序协议、声明方法
另外需要注意的是如果在结构体方法内部修改结构体的属性需要使用muating来修饰(具体原因是结构体内部默认参数self是常量,mutating修饰之后变成了inout修饰进而传递地址)
struct Text1 {
var title:String = ""
mutating func pringtTitle() {
title = "sdfghn"
print(title)
}
}
枚举
enum Name:String {
case dos
case cc = "dsdsd"
case bb
case dd
}
Name.dou.RawValue
Swift 枚举中枚举原始值类型需要显示的写出来,可以是字符串,字符,或者任何整型值或浮点型值,可以通过RawValue(编译之后生成的一个计算属性)来访问
枚举中可定义方法、计算属性、遵循协议、类型属性
枚举关联值:
如果枚举的值无法满足信息的传递,例如我想传递的是我自定义的对象,可以使用关联值,但是有了关联值就不能定义原始值
枚举的匹配:
同样是switch、if 判断
闭包表达式
闭包就是一个捕获了上下文常量、变量的函数,其实可以简单理解为oc的block只是语法上不通,下面是官方文档给出的示例
和block一样,闭包实际也是一个引用类型,可以当做参数传递,可以声明为属性、捕获属性、循环引用也是同理
和block有nsmalloc和你说stackblock一样,闭包也分堆栈空间,这也是逃逸闭包和非逃逸闭包的区别也就是说闭包要在当前声明的作用域以外使用则需要声明为逃逸闭包,逃逸闭包的内存空间在堆上
闭包表达式
{(parameters) -> return type in
statements
}
没有参数的话就是 {}
协议:
protocol Name {
var
func
}
1、swift 协议所有方法都必须实现也就是说没有 @optional 只能req
2、协议可以当做类型传递 不需要 id<protocol>delegate
扩展
swift没有分类的一说,主要使用扩展,不同于OC @interface swift kextension 可以提供方法、方法实现、定义计算属性,所以扩展就可以满足我们对于分类、扩展的需求
泛型
1、占位类型名,通过实际传入的数据来推断
2、可以进行类型约束 T: SomProtocol 要求传入的泛型是遵循协议的
其他:类型转换 as、 is 、可选链、下标脚本、访问限制
循环 for (int i , i < , I++)被干掉了只剩for in,其他的循环语句条件判断基本一致