sizeof 不是函数,在汇编里面,没有掉callq
类型分类.png
@inline
内联-1.png
内联-2.png
内联-3.png
@inout
inout-1.png
- 传的是内存地址(引用传递)
inout-3.png
可选绑定-1.png
空合并运算符 ??
空运算符-1.png
空运算符-2.png
guard语句
guard-1.png
隐式解包
隐式解包-1.png
enum
enum TestEnum{
case test1(Int,Int,Int)
case test2(Int,Int)
case test3(Int)
case test4(Bool)
case test5
}
var e = TestEnum(10,20,30);
- 上面最后一句代码,就是把10、20、30放在e的内存地址上
mov $0xa, 0x4eb(%rip), // rip存储的地址就是 0x4bdf
leaq 0x4bdf(%rip)
- rip存储的是指令的地址
- CPU要执 行的下一条指令地址就存储在rip中
结构体和类区别
- 结构体(值类型,枚举也是值类型),类引用类型
class Size{
var width = 1;
var height = 2;
}
var size = Size();
size是指针,放在内存的栈空间,占8个字节
size指针变量地址,在堆空间,Size对象的内存地址 ,占32个字节,看堆空间的绿色一共4个,4*8=32
1.png
图中蓝色和绿色 内存数据那块,一格表示8个字节。
对象堆空间申请内存过程
对象堆空间申请内存过程.png
值类型.png
闭包
闭包.png
-
fn里面前8个字节存储的是getFn里面plus函数地址,后面8个字节存储的是堆空间的地址。 -
fn(1),1这个参数在汇编里面是通过rdi寄存器传进来的,一直存储在rdi寄存器里,到了plus函数里,直接从rdi寄存器拿出来就行。 -
num是存储在堆空间里面的,向堆空间申请了24个字节,前8个字节跟类一样,指向类型信息,再8个字节,放引用计数,最后8个字节,放num。 -
在
plus里面可以拿到堆空间地址,再调用plus函数的时候,传了2个参数,一个是参数i,一个是堆空间地址值 -
num是在调用getFn函数时,函数返回时,把num传到堆空间里的 -
调用一次
getFn函数,就会开辟一次堆空间
闭包2.png
-
plus没有捕获外部变量 - 上图中
fn1占16个字节,前面8个字节,放的是plus地址,后面8个字节是0
闭包3.png
-
fn1里num在堆空间里的值是14,汇编看是捕获了2次,第一次是11,第二次是14。
全局变量
全局变量.png
- 上面代码
fn1是函数plus地址,前面8个字节是plus地址,后8个字节是0 - 全局变量,不会发生捕获,不算闭包
闭包:函数+捕获的变量。
闭包-4.png
-
上面代码调用一个
getFns只会开辟一次堆空间,这个意思是num1和num2各自只开辟一次堆空间,不是说调用plus的时候开辟一次,调用minus的时候开辟一次。 -
num1只alloc了一次,开辟了一次堆空间,前8个字节存储类型,中间8个字节存储引用计数,最后8个字节存储num1 -
num2也只alloc了一次,开辟了一次堆空间,前8个字节存储类型,中间8个字节存储引用计数,最后8个字节存储num2 -
num2和num1是分开来存储的,
自动闭包
自动闭包.png
??运算符.png
属性
属性-1.png
存储属性.png
计算属性
计算属性.png
枚举
枚举.png
枚举变量占一个字节来存储对应的case。
那么原始值存储在哪?
-
原始值不存储,是个只读的计算属性。
枚举的rawValue.png
延迟存储属性lazy
lazy.png
lazy-2.png
延迟属性的特点-1.png
属性观察器
属性观察器-1.png
属性观察器-2.png
全局变量和局部变量.png
inout在各个属性之间的地址取值
-
引用传递
代码-1.png
代码-2.png
代码-3.png
存储属性
test(&s.width)
- 上面代码
width是存储属性,有地址值,存储在s里面,所以test函数结束到的是s的地址值,又因为width是s的第一个属性,所以传s的地址值是一样的。
计算属性
test(&s.girth)
- 上面
girth是计算属性,计算属性本身没有地址值,首先,调用get方法拿到返回值,放到局部变量里面去,第二,把局部变量的地址值传给test函数,test函数把20赋值给局部变量,最后把局部变量赋值给girth,调用set函数`
属性观察器
test(&s.side)
-
side是属性观察器,先调用test函数,在test函数里面进行赋值的时候,会调用set函数,在set函数里会触发willSet和didSet函数。
传值过程 - 调用test之前,先把side里面的内容赋值给
局部变量,
- 调用test之前,先把side里面的内容赋值给
- 将
局部变量的地址值赋值给test函数,test函数修改完局部变量的值
- 将
- 将
局部变量的值,传递到set方法里, -
willSet的newValue就是局部变量的值 - 将
局部变量的值放到set的存储属性里面 - 赋值完之后调用
didSet - 真正修改
side的值,是在test函数调用完毕之后,才去改的。 -
test函数是一个独立的函数,只接收一个地址值,修改这个地址值里面的数据。
inout总结
inout总结.png
类型属性
类型属性.png
类型属性-count.png
- count只有一份内存
类型属性细节
类型属性细节.png
单例模式
单例.png
- 类型属性的最好应用
class Car{
static var count = 1;
}
Car.count = 11;
- count是lazy属性,是在第一次调用的时候才初始化,初始化的时候调用了
swift_once函数,swift_once函数里调用了dispatch_once函数,就等价于 - count是
存储类属性,线程安全,调用dispatch_once
dispatch_once({
Car.count = 1;
})
-
存储类属性是全局变量,只不过编译器限制了他的访问量
方法
方法.png
self.png
mutating
mutating.png
discardableResult
discardableResult.png
下标--subscript
下标.png
下标-2.png
下标细节
细节-1.png
细节-2.png
结构体和类作为下标返回值区别
区别.png
- struct Point
pm[0].x = 11;
等价于
pm[0].x = Point(x:11,y:pm[0].y);
pm[0].x = 掉的是set方法
- class Point
pm[0].x = 11;
- 相当于掉了下标里面的
get方法,把point返回,point是一个指针变量,你可以拿到指针变量,去修改这个地址的值了。所以不报错, - 要是换成
struct的Point,下标函数里没有set方法,pm[0].x = 11;就会报错,因为值类型,内容是拷贝赋值给一个新的临时变量,改不了旧的。
接收多个参数的下标
接收多个参数的下标.png
接收多个参数的下标-1.png
重写类型方法、下标
重写类型方法、下标.png
1.png
2.png
- SubCircle里面依然有8个字节来存储radius属性,要不然赋值没地方存。
var subCircle = SubCircle()
subCircle.radius = 10;
打印的结果为
SubCircle getRaius
Circle getRaius
SubCircle setRaius
从父类继承过来的存储属性,都是有存储空间的。不管要不要写成计算属性
- SubCircle里radius属性,get方法里return super.raius 改成raius,直接死循环了,因为不知道拿谁的raius
- 计算属性是有get、set方法
重写实例属性
重写属性.png
重写类型属性
重写类型属性.png
-
存储属性本身不让被class修饰
不让class修饰.png
属性观察器
属性观察器.png
-
父类有属性观察器
父类有属性观察器.png
-
子类可以给父类的计算属性添加属性观察器
计算属性.png
打印的结果为 Circle getRadius 是 oldValue,因为在赋值之前,要拿到对应的值
final
final.png
结构体不存在继承,所以不存在重写,在编译阶段就把函数地址、属性写死了。
初始化器
初始化器.png
- 调用规则 从它的直系父类调用指定的初始化器,这是为了保证父类初始化里面一系列操作可以正常执行。
初始化器相互调用
初始化器相互调用.png
2段式初始化
2段式初始化.png
安全检查
安全检查.png
1.png
2.png
重写
-
便捷初始化器不能被子类调用。
重写.png
重写第一条的解释.png
重写第二条的解释-1.png
重写第二条的解释-2.png
- 子类无法去覆盖Person类的
convenience init()方法的,convenience init()只能在Person类里其他调用,子类掉用不了,不算重写
自动继承
自动继承.png
第一条规则的解释.png
第二条规则的解释.png
required
required.png
属性观察器
属性观察器.png
可失败初始化器
可失败初始化器.png
反初始化器 deinit
deinit.png
可选链 Opitional Chaining
可选链 .png
协议 Protocol
协议1.png
协议2.png
static class
static-class.png
- static不可以子类重写,class子类可以重写
mutating
mutating.png
init
init.png
init-2.png
- 上面的Student 里面required 来自协议,override来自父类
init 、init?、init!
init 、init?、init!.png
协议2.png
协议3.png
CaseIterable
CaseIterable.png
-
allCases返回一个数组
CustomStringConvertible CustomDebugStringConvertible
-
CustomStringConvertible里面有description
CustomStringConvertible.png
CustomDebugStringConvertible.png
Any AnyObject
Any AnyObject.png
**is as? as! as **
is as? as! as.png
X.self、X.Type、AnyClass
- X是类
Person.self 放元类地址
跟person对象的前8个字节存储的地址一样
1.png
元类型的使用
元类型的使用.png
继承
继承.png
继承2.png
Self
-
跟OC里面的instanceType差不多
Self.png
Self-2.png
4句都调用了init.png
error 错误类型
开发错误.png
自定义错误
自定义错误-1.png
do-catch
do-catch.png
处理Error
处理Error.png
代码.png
try? try!
try? try!.png
-
try?异常是nil,不异常是Option值 -
try!告诉系统一定没错, 如果发生错误, 程序会崩溃. 不推荐使用 - 首先要明白抛出异常后异常的运动:异常被抛出后,中断整个处理,异常不断向外层(范围)传递,直到遇到catch代码块群,会与catch代码块的条件进行匹配,匹配符合则进入此代码块处理。如果遇到没有条件的catch{}那么直接在这个代码里处理。如果抛出的异常一直到最外层仍没有被catch{}处理,那么程序会卡住(后面的处理全部中断)
rethrows
rethrows.png
defer
defer.png
- 一段代码,不管你是正常执行完,还是直接崩溃跳出代码,之后,需要做的操作,比如读数据库,不管是正常读完,关闭数据库,还是SQL写的不对直接崩溃,退出,关闭数据库,在
defer执行。
泛型
泛型-1.png
泛型属性
泛型属性.png
关联类型(Associated Type)
关联类型.png
类型约束
类型约束-1.png
类型约束-2.png
equal.png
-
equal函数的意思是:S1、S2必须遵守Stackable协议,S1、S2的关联对象必须一致,S1的关联对象Element必须遵守Hashable协议,多要求的话必须在返回值后面加where关键字
协议类型的注意点
协议类型的注意点.png
泛型解决一
解决一.png
泛型解决二---不透明类型(Opaque Type)
-
不透明类型使用场景:返回一个遵守某种协议的对象,拿给别人用,但是又不告诉别人具体是那种类型,而且别人拿到的接口仅仅是协议里面的接口,用不透明类型
解决2-some.png
some-2.png
assert断言
assert.png
-
do-catch不可以捕获
fatalError
fatalError.png
访问控制Access Control
- 实体 ,下面
name就是实体
class Person{
public var name = ""
}
模块.png
-
open其他模块可以继承、重写
open class Person{
open var name = ""
}
-
internal只能在当前实体里使用,不能当做第三方库被别人使用
internal class Person{
var name = ""
} -
fileprivate加入在main.swift里定义了一个Person类,那么Person类只能在main.swift文件中使用 -
private, 下面name只能在Person{}这个大括号里使用
class Person{
private var name = ""
}
访问控制.png
- 绝大部分实体都是
internal级别
访问级别的访问准则
1.png
变量类型>= 变量的访问级别.png
父类型>=typealias.png
原始值类型.png
定义A类型.png
元组类型
元组类型.png
泛型类型
泛型类型.png
成员、嵌套类型
成员、嵌套类型.png
1.png
-
上面代码在全局作用域中,2个作用域类型是一样的。private和fileprivate是一样的
-
private是在定义的文件里访问,在全局作用域,就是当前的文件里都能访问
2.png
-
private和fileprivate是在Test里面,不符合
父类高于子类的规定。
4.png
- 上面Dog是private,但是在全局作用域里,private相当于fileprivate,那么age也是fileprivate
直接在
全局作用域下定义的private等价于fileprivate
重点
5.png
- 首先上面代码是运行成功的。
问Person里面的dog.run()为啥不报错
-
因为Dog和Person都是private修饰,意味着Dog是在Test类里可以使用,那么Dog的run()函数和age都是可以在Test类里使用的
6.png
- 上面代码
age加了一个private,那么age只能在定义它的实体里使用,也就是在Dog里面使用,外部使用不到。
getter setter
getter setter.png
初始化器
初始化器.png
结构体.png
- 一旦上面的y是private,那么Point(y:10)会报错,因为带y的初始化器只能在Point里面使用
枚举
枚举.png
协议
协议.png
- 针对于最后一条理解:协议有定义协议的访问级别,有实现协议里面方法的访问级别,当
实现协议里面方法的访问级别>=定义协议的访问级别,就好比下面代码
定义协议的访问级别 private
private protocol A{
run()
}
class Person:A{
实现协议的访问级别 public
public run(){}
}
- 上面代码不报错
扩展
扩展.png
扩展1.png
- Person扩展里
run()函数,在别的文件里不能被调用,只能在当前文件里调用,run()的访问级别是fileprivate
第四条解释.png
扩展2
扩展2.png
- 上面3个扩展都是在同一个文件中,相当于所有代码都在同一个类中。
将方法赋值给var/let
struct Person {
var age:Int
func run(_ v:Int){ print ("func run",age,v)}
static func run(_ v:Int){ print ("static func run",v)}
}
let fn1 = Person.run;
fn1(10); //static func run 10
let fn2:(Int)->() = Person.run;
fn2(20); //static func run 20
- 上面代码,先传一个Person实例,在调用函数run
将方法赋值给var、let-4.png
- 实例方法不用传Person实例
内存管理
内存管理.png
内存管理-2.png
自动释放池
自动释放池.png
循环引用
循环引用-1.png
闭包循环引用
闭包循环引用.png
- p强引用闭包,闭包又强引用p
闭包循环引用.png
闭包循环引用2.png
闭包循环引用3.png
-
()这个是马上调用,就把age值赋给了getAge,闭包表达式不存在了,闭包表达式self.age执行完生命周期就完了,相当于getAge本质是Int类型,getAge=self.age,所以这就不用写weak
@escaping
escaping.png
- 如果是逃逸闭包必须写self,因为影响了self的生命周期。
逃逸闭包注意点2
逃逸闭包.png
do
do.png
内存访问冲突(Conflicting Access to Memory)
内存访问冲突.png
内存访问冲突-2.png
指针
指针.png
-
UnsafeMutablePointer是可以修改指针的值的 -
pointee是可以取出指针的值的,相当于C里面的*ptr -
UnsafeMutableRawPointer不知道传递的指针是什么类型,所以storeBytes()里面的as是类型。 -
load里面的as也是类型,这个函数是取值。
代码-2.png
指针使用场景
指针使用场景-1.png
获得指向某个变量的指针
获得指向某个变量的指针.png
获得指向堆空间实例的指针
获得指向堆空间实例的指针.png
- ptr存储的是堆空间的指针,不是person 的指针
-
UnsafeRawPointer就是把指针指向的地址取出来,这里ptr3拿到的是person的地址,heapPtr指向的是person指针指向的堆空间的地址。
获得person的指针.png
- ptr存储的是person 的指针,unsafePointer传谁的值,返回谁的值,这里是person的值,返回person的值。
创建指针
创建指针.png
创建指针-2.png
- malloc 开辟了16个字节的数据,然后 store前8个字节存11,接着store(offSet)偏移8个字节,存22。
-
advanced指针挪动8个字节,返回给你一个指针,是下一个8个字节的指针,2个指针之间相差8个字节。相当于 0x00 + 8个字节 = 0x08,返回给你。 - 这里rawPointer不知道那个类型,所以得传类型。
创建指针-3.png
- 这里指定了类型Int,这是
capacity是容量,相当于开辟了2*8=16个字节。
创建指针-4.png
-
initalize是 初始化前8个字节,也就是0x000 -
successor指向的内存是 后8个字节,0x008
创建指针-5.png
- 调用了
initalize - 最后 得掉
deinitalize释放
指针转换
指针转换-1.png
-
ptr.assumingMemoryBound是把任意类型转一种类型
指针转换-2.png
- 把ptr转成Int,就相当于把二进制数据给你,然后类型发生变化,原来是任意类型,现在是Int。
字面量(Literal)
字面量.png
字面量协议
字面量协议.png
字面量协议应用
字面量协议应用.png
模式匹配
通配符
通配符-规则.png
通配符--代码.png
标识符模式
标识符模式.png
值绑定模式
值绑定模式.png
元组模式
元组模式.png
枚举case模式
枚举case模式.png
可选模式
可选模式.png
-
?非nil,非空值
类型转换模式
类型转换模式.png
自定义模式
自定义模式.png
自定义模式表达式
自定义模式表达式.png
where用处
where.png
OC到Swift
标记
标记.png
编译条件
编译条件--1.png
编译条件--2.png
系统版本检查
系统版本检查.png
API可用性
API可用性.png
Swift掉OC
Swift掉OC--1.png
person.h.png
person.m.png
Swift调用.png
Swift掉OC --- @silgen_name
Swift掉OC --- @silgen_name.png
OC掉Swift
OC掉Swift .png
OC掉Swift -代码.png
OC掉Swift-@objc.png
选择器Selector
选择器Selector.png
1. 为啥Swift暴露给OC的类最终要继承NSObject?
- 这个类是在OC里面用,在OC里面用肯定得继承NSObject,得有isa指针,最终走objc_msgSend。
- OC依赖与runtime,runtime要求类有isa指针,isa指针肯定继承NSObject。
2. Swift类调用OC类里方法,是怎么调用的?反过来OC调用Swift又是怎么调用的? - 纯Swift掉方法是走虚表那套机制
Call 0x0xxxx 找这个地址
- Swift掉OC的方法,还是走的objc_msgSend机制
- OC掉Swift的方法,肯定也是走objc_msgSend,因为继承NSObject,然后依赖isa
下面的类里run怎么走?
Swift类.png
- 还是走Swift虚表这套。在Swift里面,肯定走Swift里面的效果。
String
字符串一.png
插入和删除.png
-
endIndex指的是2后面的位置 -
startIndex指的是1的位置
Substring
Substring.png
substring流程.png
- string为Hello,world 然后Substring那你截取的话,Substring同样指向
Hello,world的地址,2个公用一份地址,然后把数据返回, - 如果要把Substring类型转成string,那么就得吧Substring地址的数据深拷贝出一份,形成一个新的地址。
Substring.png
String相关协议
String相关协议.png
多行String.png
String和NSString
String和NSString.png
Swift和OC桥接转换表
Swift和OC桥接转换表.png
- 上面的是直接
as
只能被class继承的协议
协议--1.png
协议--2.png
dynamic
dynamic.png
KVC、KVO
KVC、KVO.png
block版本的KVO
block版本的KVO.png
关联对象
关联对象.png
-
Void是一个字节,不浪费内存
资源名管理
资源名管理-1.png
资源名管理-2.png
资源名管理的其他思路
资源名管理的其他思路.png
多线程开发---异步
多线程开发---异步.png
数组操作map
- map会遍历元素,遍历一次,调用一次闭包,然后将元素传给你,操作,然后返回一个值,然后将返回值,放到一个新的数组,返回给你。
数组操作filter---过滤
- filter会遍历元素,遍历一次,调用一次闭包,然后将元素传给你,操作,然后返回一个Bool值,如果返回为true,那么就返回到数组里面去
数组操作reduce
reduce.png
- reduce函数,接收2个参数,第一个参数初始值,第二个参数闭包返回值为result,类型跟初始值一样。
- 循环遍历数组中每个元素,第一次遍历,result为初始值,上面代码为0,element为1,2个数值相加,作为下次循环的result--
1 - 第二次循环,也就是2了,element为2,result为第一次循环的结果
1,然后2者相加,结果result3,作为下次循环的结果, - 始终result作为下次循环的参数,和element相加,一直到循环结束,赋值给
arr2 - 这里就相当于0+1+2+3+4
截屏2021-10-25 下午2.13.47.png
map和flatmap区别
- (1)flatMap返回后的数组中不存在nil,同时它会把Optional解包
let array = ["Apple", "Orange", "Puple", ""]
let arr1 = array.map { a -> Int? in
let length = a.characters.count
guard length > 0 else { return nil }
return length
}
arr1 // [{some 5}, {some 6}, {some 5}, nil]
let arr2 = array.flatMap { a-> Int? in
let length = a.characters.count
guard length > 0 else { return nil}
return length
}
arr2 // [5, 6, 5]
- (2)flatMap还能把数组中存有数组的数组(二维数组、N维数组)一同打开变成一个新的数组
let array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let arr1 = array.map{ $0 }
arr1 // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let arr2 = array.flatMap{ $0 }
arr2 // [1, 2, 3, 4, 5, 6, 7, 8, 9]
- (3)flatMap也能把两个不同的数组合并成一个数组,这个合并的数组元素个数是前面两个数组元素个数的乘积
let fruits = ["Apple", "Orange", "Puple"]
let counts = [2, 3, 5]
let array = counts.flatMap { count in
fruits.map ({ fruit in
return fruit + " \(count)"
})
}
array // ["Apple 2", "Orange 2", "Puple 2", "Apple 3", "Orange 3", "Puple 3", "Apple 5", "Orange 5", "Puple 5"]
- map:可以对数组中的每一个元素做一次处理
compactMap
- 当闭包中的返回结果是可选的时候,使用compactMap代替flatMap,那么当闭包中的返回结果不是可选的时候,依然使用flatMap。
let arrayString = ["Ann", "Bob", "Tom", "Lily", "HanMeiMei", "Jerry"]
let arrayInt = arrayString.compactMap { (str) -> Int? in
return str.count
}
print("arrayInt: \(arrayInt)")
// arrayInt: [3, 3, 3, 4, 9, 5]
// 简化
let arrayInt2 = arrayString.compactMap { $0.count }
print("arrayInt2: \(arrayInt2)")
// arrayInt2: [3, 3, 3, 4, 9, 5]
let arrayI = arrayString.compactMap { $0.contains("i") ? $0 : nil }
print("arrayI: \(arrayI)")
// arrayI: ["Lily", "HanMeiMei"]
- 结果可以看出,虽然闭包返回值是可选的,但是真正返回的结果中,并不是可选的,也会过滤掉nil的情况。
lazy的优化
lazy的优化.png
lazy的优化-2.png
- 看上面代码
lazy在需要的时候才去进行操作,而且result[1]的时候,只是去map2这一个元素,当这数据量大的时候,可以使用lazy进行优化。
option的Map和flatMap区别
option的Map和flatMap区别.png
option的Map
- 如果有值,那么取值以后进行map操作,操作再加一层Option,那么返回的是
??这种格式 - 如果没值,那么直接返回nil
option的flatMap - 如果有值,那么取值以后进行flatMap操作,操作再加一层Option,那么返回的还是
?这种格式
高阶函数
高阶函数.png
柯里化Currying
柯里化.png
函子(Functor)
函子-1.png
函子-2.png
适用函子(Applicative Functor)
适用函子--1.png
适用函子--2.png
单子(Monad)
单子.png
-
F是类型
面向协议编程
面向协议编程-1.png
OOP
OOP.png
OOP不足
OOP不足.png
POP解决方案上面不足
POP解决方案-1.png
POP注意点
POP注意点.png
计算属性
- 内存里没有一个存储属性来指向他
- 本质是方法
利用协议实现前缀
利用协议实现前缀-1.png
Base代码.png
Base协议
-
Base后面继承一个协议
Base协议.png
利用协议判断类型
利用协议判断类型--1.png
响应式编程
响应式编程.png
RXSwift
RXSwift.png
RXSwift核心角色
RXSwift核心角色--总览.png
创建、订阅Observable1
创建、订阅Observable1.png
Observable.just(1111)
等同于
// 发送消息
observable.onNext(22222)
// 发送多个消息,然后接收方 接收3次
Observable.of([1,2,3])
// 发送多个消息,然后接收方 接收3次
Observable.from([1,2,3])
Observable.of和Observable.from打印结果.png
创建、订阅Observable2
创建、订阅Observable2.png
-
seconds(3)3秒之后再发消息 -
period: .seconds(1)周期,3秒之后,每隔1秒再发消息 -
scheduler:MainScheduler.instance 主线程 -
上面就是个定时器
Disposables
Disposables.png
-
DisposeBag()是上面bag对象 -
self.rx.deallocated跟随着self的生命周期,当self销毁的时候,自动释放。 -
bind把数据绑定到对应的控件上去
创建Observer
创建Observer.png
扩展Binder属性
-
Binder是Observe
扩展Binder属性.png
RXSwift的状态监听1
RXSwift的状态监听1.png
RXSwift的状态监听2
RXSwift的状态监听2.png
即是Obeservale又是Obeserver
1.png
-
ControlProperty即是Obeservale又是Obeserver
即是Obeservale又是Obeserver.png
Swift源码
Swift源码简介-1.png
Swift源码地址.png
Array源码分析
map源码
map源码.png
-
interator迭代器,interator.next()迭代器拿到一个元素,传到transform()函数里面,并且把transform()的返回值放到result里。 - 最终把
Array(result)返回
filter源码
filter源码.png
- 调用
_filter函数 -
isInclude()函数,就是filter穿进去的判断函数, -
interator迭代器,interator.next()迭代器拿到一个元素, - 把这个元素传给
isInclude()函数,返回true,将这个元素拼接到result数组里面 - 最终把
Array(result)返回
flatMap compactMap reduce
flatMap
flatMap.png
- 定义一个
result数组 - 循环遍历,拿到element,传给
transform函数 - 把结果添加到
result里 - 返回
result
compactMap
compactMap.png
-
compactMap函数调_compactMap -
_compactMap函数,循环遍历元素,然后判断元素不为nil,添加到result里 -
返回
result -
`compactMap函数 去掉数组中的nil值
Substring
Substring--1.png
Substring--2.png
-
base函数,拿到之前指向的字符串,是因为返回_slice.base,就是外面传进来的字符串 -
_slice.base里bounds记录着字符串是那段区域
Substring.png
Substring的append方法
Substring的append方法.png
-
var string = String(self),append函数里,substring把自己穿进去,创建一个新的string, - 然后创建一个新的地址,把原来内容拷贝进去,
- 把外面传进来的内容,拼接到新的string里
- 然后再拿新的string创建一个新的Substring
Opition的map和flatMap源码
flatMap
flatMap.png
- 枚举值,先判断自己是否有值,如果是
.none,就是没值,返回.none - 如果有值 取出来赋值给y,调用
transform函数, - 返回
transform函数的值
map
map.png
- 枚举值,先判断自己是否有值,如果是
.none,就是没值,返回.none - 如果有值 取出来赋值给y,调用
transform函数,拿到返回值, - 再包装一层
.some(返回值)返回回去
区别
- 就是在有值,返回的时候,flatMap是直接返回
transform函数的值 - map是包装一层
transform函数的值,.some(transform(y));
Opition的==号
==代码1.png
-
==左边有值,右边为nil
==代码2.png
-
上述代码可以看出
rhs可以为nil,因为继承的协议可以初始化为nil
var age :Int? = 10
print(age == nil)
会触发上面的==代码
- 判断
lhs是不是为nil,如果是nil返回true,如果有值返回false
var age :Int? = 10
print(nil == age)
会触发下面的代码
-
左边为nil,右边有值
==代码3.png
==比较2个正常的值
==比较2个有值.png
var age1 :Int??? = 10
var age2 :Int? = 10
var age3 :Int = 10
print(age1 == age3)
print(age1 == age2)
print(age2 == age3)
- 先拿到左右2边的值,左右2遍的值能解包,就取值,返回
左边值 == 右边值这个判断 - 如果2个值都是nil,返回true
- 默认返回为false
Opition的??号 源码
var age1 :Int? = 10
var age2:Int? = 10
print(age1 ?? age2)
??代码1.png
??代码2.png
-
??一个返回值是T,一个是T? - 都先判断左边的值是否有值,拿到左边的值先解包,有值都返回
value,如果返回是T?,不代表返回的就是可选类型。 - 左边有值,肯定得解包一次
- 没值,返回,调用右边的
defaultValue闭包
Metadata分析
class Person{}
var person = Person()
- person指向堆空间,前8个字节指向
Metadata - 中间8个字节是引用计数
- 在后面就是属性变量、函数等等
Metadata
-
Metadata分类型的,struct、protocol、class的Metadata不一样。
网址.png
Metadata--类型.png
ClassMetadata
class-metadata结构.png
-
kind前8个字节,类型,是枚举、类、struct -
superclass再8个字节
反射
反射.png
关于Sting的考虑
关于Sting的考虑.png
var str1 = "0123456789"
- str1在内存里占16个字节,内存里存储的是ASCii码,
str1内存打印结果.png
- 上面是小端模式读取内存的结果,小端模式是37在前,
-
0对应的ASCII码值是30,那么9对应的值是39 - 上面
str1里面存储的值就是"0123456789" -
0xe9,a就是长度(10个字符,0~9不就是10个字符吗),a最大是f,,e是类型,表示直接存储内容, -
a最大是f,刚好填满15个字节,
存储了15个字节.png
- 上面的str1,直接将内容放到了内存中,类似于OC的
target point,直接将内容放到了内存中
var str2 = '01234567890ABCDEF'
打印地址.png
16个字符- 汇编调用函数,
返回值如果大于8个字节,放到rax和rdx - 上面的代码会调用
Swift.init初始化器,传了2个参数,一个是字符串的长度,一个是字符串的真实地址,会拿15跟字符串的长度进行比较,小于15直接存储在字符串的真实地址里, -
大于15,会把真实地址放到str2的后8个字节,因为str2是全局代码,这8个字节存储在TEXT段的Cstring段,常量区
字符串真实地址 + 0x7fffffffffffffe0 = 0x800000010000a790
也可以
字符串真实地址 + 0x20 = 0x800000010000a790
-
读取地址,拿到对应的值
真实地址.png
字符串拼接 append
- 如果拼接完字符长度
不够15,那么还是存储在内存中 - 如果
超过15,那么重新指向一块内存,那么就需要堆空间了
从编码到启动App
从编码到启动App.png
字符串拼接
字符串拼接.png
- 看打印的地址,2个前8个字节,
0xd000000010,0xf00000011,这里面11和10 ,分别是字符串的长度,d0表示在常量区, -
f0之后会调用String.init*()->malloc,重新分配地址 -
str2后8个字节放的是,append之前的地址值,这个地址值+0x20就是堆空间的地址值,
str2 append之前后8个字节地址值 + 0x20 = 拼接后字符串地址值
-
0x2032个字节,放的是堆空间信息。
字符串探讨.png
dyld_stud_bind 符号绑定
App加载流程.png
mac-o加载.png
var str1 = "0123456789"
str1.append('ABCDEF');
append调用可String.init()函数。
- 底层调用了
String.init()函数动态库,程序运行中才会把动态库载入进去,String.init()的地址,是程序启动之后才知道的, - 编译的时候。
str1的地址是临时的,占位地址 - 然后会执行
0x1000a3ce jump *0x2c4c(%rip),0x2c4c就是一个地址
rip = 0x1000a3ce + 6 = 0x100000A3D4
0x100000A3D4 + 0x2c4c = 0x100000D020
- 取出 0x100000D020的地址,然后jump
取出的值,直接拿D020,去mac-o里面查地址,
mac-o文件的地址.png
取出的地址:0x0100000A5F4
- jump跳到
0x0100000A5F4后,一直进,会来到dyld_stud_bind - 绑定完了只会,再调到
真正的String.init()函数地址。
Array 值类型
var arr = [1,2,3,4]
-
arr占用了8个字节,是一个指针,指向堆空间。
array地址打印.png
-
抛过前4个指针(32个字节),从第5个指针看,是
1
Array的结构图.png
- 上面的
容量,初始化的时候,是一定的,当元素数量超过容量的值的时候,容量会翻倍扩容(舍弃一部分空间,重新开辟一段新的内存)
可选项本质
enum.png
var age:Int? = 10
switch age {
case let v:{
print(v)
}
- 上面代码相当于直接把
let v = age,直接把age无条件赋值给了v。不管是不是nil。
溢出运算符(OverFlow Operator)
var v1 = UInt8.max;
v2 = v1.&+1;
print(v2) // 0
var v1 = UInt8.min;
v2 = v1.&-1;
print(v2) // 255
var v1 = UInt8.max;
v2 = v1.&*2; == 255 &+255
// 因为 255 &+1 = 0 255 &+2 = 1 ... 所以为254
print(v2) // 254
- 取值范围是
0~255,换算成数组长度的话就是 count = 256,如果 255 + 1 = 256 - count = 0。
溢出运算符-1.png
溢出运算符-2.png
运算符重载(Operator Overload)
运算符重载.png
-
prefix-前置
++a;
-
postfix-前置
a++;
Equatable
Equatable.png
-
Equatable继承这个协议,实现static func == () ->Bool函数
func equals <T:Equatable> (_ t1:T, _t2:T) ->Bool{ t1 == t2}
-
<T:Equatable>类型为T,都继承了Equatable协议
Comparable
Comparable--代码1.png
Comparable--代码2.png
自定义运算符(Custom Operator)
自定义运算符-说明.png
-
assugnment:true,可选链中拥有赋值一样的优先级
class Person{
var age = 0
}
func getAge() -> Int{ 10 }
var p:Person = Person();
p?.age = getAge()
赋值优先级,上面代码 p? 要是p有值,getAge()计算出结果,才会赋值给age,如果p为nil,那么就不会赋值
associativity:结合性,
- left 是从左到右计算
- right 是从右到左计算
- none 不允许出现2个以上的运算,下面代码把
left改成none会直接报错。不知道该怎么计算。
associativity.png
扩展(Extension)
扩展.png
-
存储属性、继承增加内存结构,所以扩展不能添加这些。
协议、初始化器
协议、初始化器.png
上面最后一条解释 ---- 类实现required
上面最后一条解释.png
协议
协议1.png
协议2.png
- 如果类里函数名称和协议里函数名称 一样,调用的时候,优先调用类里的函数。
泛型
泛型.png








网友评论