背景
被问到的面试题,这里记录一下。
问题
Swift 中 Struct 和 Class 的区别
Swift 中 为什么 String、Array、Dictionary 用 Struct 实现
Swift 中写时复制的原理
Swift 中变量作用域有哪些,区别是什么
Swift中 Protocol 如何声明可空
MVP 的优点是什么
RxSwift 中冷信号和热信号的区别
RxSwift 中 CombineLatest、zip、merge的区别
Git 中 rebase和 merge 的区别,rebased的 commitID 会改变吗
SwiftUI 中 View 传值方式有哪些
什么情况下触发 layoutSubviews
答案
Swift 中 Struct 和 Class 的区别
Struct是值类型,Class 是引用类型;
Struct和 Class 都可以有属性和方法,但是 let 修饰的 Struct 不能更改,Class 修饰的可以更改;Struct方法中修改属性需要在方法前添加 mutating 关键字。
Struct和 Class 都可以实现协议。
Struct不能被继承,Class 可以。
Class 在实例化的时候不能自动把property 放到 constructor 中,Struct 可以。
Swift 中 为什么 String、Array、Dictionary 用 Struct 实现
- 安全:值类型不可变,传递值类型实际上传递的是一份副本,不用担心函数内对值的修改影响到外部数据,有助于减少程序中的错误,不用担心数据在未预期的情况下被修改掉。
- 简化并发编程:值类型不可变,多个线程访问和修改的都是值类型的副本,从而避免了数据竞争和同步的问题,简化了并发编程的安全性。
- 语义清晰:值类型更符合某些数据结构的自然语义。比如字符串是不可变的文本序列,设计为值类型能更好的反映这些数据结构的使用方式和预期行为。
- 优化性能:Swift使用写时复制技术避免不必要的复制,确保复制是性能上可以接受的。对于大型数据结构,值类型的语义可以提醒开发者更谨慎的处理数据,从而减少不必要的性能开销。
Swift 中写时复制的原理
写时复制(Copy-On-Write)是一种内存优化技术,原理是需要修改数据时才进行拷贝,避免不必要的内存操作。Swift 在修改数据时,会判断数据在其他地方是否被引用,如果被引用则先拷贝再修改;如果没有引用,则直接在原数据上修改。这样只有实际需要修改时才拷贝,就减少了内存开销。
对于 String、Int 等简单数据的值类型,赋值的时候就会发生拷贝,因为对于这些类型来说写时复制的开销比直接复制的大。对于Array、Dictionary、Set等类型,做了优化,只有传递的值发生改变时,才会拷贝数据。
Swift 中变量作用域有哪些,区别是什么
open > public > internal > fileprivate > private
open 和 public 都可以访问模块外的属性或方法,区别在于 open 修饰的可以在模块外继承或者重写,而 public 修饰的不能被集成或者重写。
fileprivate 和 private 的区别在于,fileprivate 是当前.swift文件内都可访问。private 是当前类内可访问。(在一个.swift 中有多个类的情况下,就能体现出 fileprivate 和 private 的区别)。
internal是swift 文件的默认权限,在当前模块内可访问,模块外不能访问。
Swift中 Protocol 如何声明可空
optional
MVP 的优点是什么
MVP 是 Model管理数据,View 负责展示,Presenter 负责管理业务逻辑,View 通过接口与 Presenter 交互,降低耦合,方便单元测试。 Presenter 实现了 View 与 Model 的分离,View 中不包含任何业务逻辑,且不直接与 Model 交互。
MVP 的优点是:
- 模型与视图分离,从而改变视图的时候不会影响模型
- 可以更高效的使用模型,所有的交互都发生在 Presenter 内部
- 可以将一个 Presenter用于多个视图,不需要改变 Presenter 的内部逻辑。视图的变化总比模型变化频繁。
- 逻辑放在 Presenter 中,可以脱离用户接口来测试这些逻辑。
缺点是:
视图与 Presenter 交互过于频繁,可能导致联系过于紧密,一旦视图变化,Presenter 也需要变更。
RxSwift 中冷信号和热信号的区别
冷信号是只有在有订阅的时候才发送事件,每次发送会把之前所有的事件都重新发送一遍,会为每个订阅者单独执行一次发射数据的代码。通常是无状态的。
热信号是一旦有事件就发射,不管有没有被订阅。新的订阅者并不会接收到订阅前已经发送的事件。通常是有状态的。
RxSwift 中 CombineLatest、zip、merge的区别
merge 是把多个序列合并成一个,当任一个序列发送事件时,合并后的序列就发送。
CombineLatest 是把多个序列通过函数组合成一个,当任一序列发送事件时,组合后的序列就触发。
zip是把多个序列通过函数组合成一个,但是当所有序列都有事件发生时,才发送,且每个事件只发送一遍。
Git 中 rebase和 merge 的区别,rebased的 commitID 会改变吗
rebase 合并之后,原 commit 会合并到target分支上,相当于是按时间把之前分支每个 commit 都merge 到了target 分支,commitID 会改变。
merge 是把原分支合并到 target 分支,合并之后原分支的 commit没有改变,如果删除原分支,则 commit记录 就丢失了。
rebase 之后的 commitID 会改变。
SwiftUI 中 View 传值方式有哪些
@State、@Binding属性包装器
@EnvironmentObject
@ObservedObject
@Environment
@AppStorage
什么情况下触发 layoutSubviews
- init的时候不会触发,initWithFrame 且 frame 不为 CGRecZero 的时候会触发
- addSubview会触发
- view 的 frame 改变的时候会触发
- 滚动 UIScrollView 的时候会触发
- 旋转 View的时候会触发父 View的layoutSubviews
- 改变View 的大小的时候会触发