iOS面试题:Swift
swift 和 oc 的区别?重点
swift
是静态语言
,有类型判断
。OC
是动态语言
。Swift
是类型安全
的语言。OC
类型不安全的语言。swift
可以面向函数、协议、对象
编程。OC
以面向对象
编程为主。Swift
注重值类型
。OC
注重引用类型
Swift
支持静态派发、动态派发(函数表派发、消息派发)
。OC 支持动态派发(消息派发)
swift
代码更简洁、运行速度更快、性能更好。
静态语言:静态类型语言,
数据类型
是在编译
期间检查的语言
动态语言:动态类型语言,数据类型
是在运行
期间检查的语言
OC和Swift 方法的调用 区别?重点面试题
OC
支持动态派发(消息派发)
,运行时才确定方法的实现。swift
支持静态派发和动态派发
来确定方法的实现。
静态派发
静态派发是指在
运行时
调用方法不需要查表
,直接跳转到方法的代码中执行。静态派发是有条件的,方法内部的代码必须对编译器透明,并且在运行时不能被更改,这样编译器才能帮助我们。
Swift中的
值类型
不能被继承,也就是说值类型的方法实现不能被修改或者被复写,因此值类型的方法满足静态派发
的要求。class
中将方法标记为。final
或者private
就是静态调度。内联是指在编译期把每一处方法调用替换为直接执行方法内部的代码,可以帮助你避免运行时方法调用的时间开销。
动态派发
动态派发
需要查表
。即函数表调用
Swift中的
类
会创建一个V-Table
,这个Table是一个数组,其中存放的是函数指针
。子类会按照父类
V-Table
中函数的存放,如果子类没有覆盖某个方法,那么就会拷贝父类方法的地址,如上面的例子会得到下面的V-Table。将函数指针和Index所做的映射在编译期就确定了,这就大大减少了运行时的工作量,提高了运行速度。所以在运行时它没有必要知道是哪个类型的实例调用了这个方法,只需要找到相应的V-Table即可,至于是其中的哪个Index,已经在编译期确定了,没必要再去查找Index的值。
权限修饰符 面试重点
open:修饰的属性或者方法在
其他作用域既可以被访问
,也可以被继承或重载 override
。public :修饰的属性或者方法可以在
其他作用域允许被访问
,但不能被重载,也不能在继承的 Extension 中被访问
。internal:被修饰的属性和方法只能在
模块内
部可以访问,超出模块内部就不可被访问了。(默认)fileprivate :其修饰的属性或者方法只能在当前的
源文件
里可以访问。private :只允许在
当前类
中调用,Extension
中不能访问从高到低排序如下:
open > public > interal > fileprivate > private
swift 是面向对象还是函数式编程? 重点
swift 既是面向对象也是面向函数式编程
swift面向对象,是因为swift支持
类的封装、继承、多态
swift面向函数式编程,是因为swift支持
map、reduce、filter、compactMap、flatMap
这类去除中间状态、数学函数式方法
,更加强调运算结果
而不是中间过程。
swift中高阶函数有几种?分别讲解一下? 重点
map
对给定数组每一个元素,执行闭包中的映射
操作,将映射结果放置在数组中返回
1 | // 数字数组子元素转换为字符串 |
filter
对给定数组的每一个元素,执行闭包中的过滤
操做,将符合条件的元素放在数组中返回
1 | // 筛选偶数 |
reduce
对给定数组的每一个元素,执行闭包中的合并
操作,并将合并结果返回
1 | // 转换为字符串并拼接 |
compactMap
对给定数组的每一个元素,执行闭包中的映射
操作,将非空的映射结果放置在数组中返回
1 | let arr2 = [1,2,3,nil]; |
flatMap
对给定数组的每一个元素,执行闭包中的降维
操作,将映射的结果防止在数组中返回
1 | let arr3 = [[1,2],[3,4]]; |
什么是类?什么是结构体?重点
struct
和 class
都是 构建代码的一种通用且灵活的构造体。
struct 和 class 区别? 重点
struct、class 共同点:
- 定义
属性
用于存储值
- 定义
方法
用于提供功能
- 定义
下标脚本
用于访问值
- 定义
初始化器
用于生成初始化值
- 定义
扩展
以增加默认实现的功能
- 定义
协议
以提供标准功能
- 定义
struct、class 不同点:
- class 定义
属性
,必须赋值或包装成Optional
。struct 定义属性不需要要赋值 - class 是
引用类型
,分配在堆
中,动态分配释放内存,浅拷贝
。struct 是值类型
,分配在栈
中,系统分配释放内存,深拷贝
。 - class
可以继承
,。struct不能继承
。 - class 有
引用计数
,可以多次引用
。struct 没有引用计数 - class 有
类型转换
,允许在运行时检查和解释一个类实例的类型
。struct 没有 - class 有
反初始化器 deinit
用于释放资源
- struct 比 class
更轻量级
,栈
只访问一次拿到数据,堆
访问两次拿到数据(第一次
获取指针,第二次获取数据)
- class 定义
类的指定初始化器和便捷初始化器?
类的初始化器代理规则
- 指定初始化器必须调用其直接父类的指定初始化器
- 便捷初始化器必须调从同类调用一个指定初始化器
- 便捷初始化器最终必须调用一个指定初始化器
更方便的记忆方法
- 指定初始化器必须总是向上代理
- 便捷初始化器必须是横向代理
什么是闭包?重点
代码中可以 被传递和引用的功能性独立的代码块
闭包作用?重点
闭包
可以捕获和存储上下文的常量和变量
,闭包
实现上是一个结构体
闭包
可以作为函数参数
,也可以作为函数的返回值
闭包可以像
oc
中用于回调和反向传值
闭包的几种类型?重点
尾随闭包:
闭包作为函数最后一个参数
逃逸闭包:用
@escaping
修饰,函数返回之后调用自动闭包:用
@autoclosure
修饰,延迟执行,即调用的时候才执行
Optional是什么?
Object-C
中用nil
表示指向不存在对象的指针
,其他地方用NSNotFound
表示值缺失
Swift
中用可选(Optional)类型
表示值缺失
,只有可选类型才能设置为nil
Optional
含有两种枚举,None
和Some(T)
,用来表示可能有值或可能没有值
。Swift
中只有Optional
才能设置为nil
,用?
或Optional<数据类型>
如何使用 Optional?
强制解包:
!
数据类型:
!= nil
可选绑定:
if
赋值给常量或变量隐士解包:直接
!
初始化值
swift类型?Swiift 值类型 和 引用类型的区别?特点?
swift的类型分为
值类型
和引用类型
。值类型:如
struct、enum、Int、Float、Bool、String、Array、Dictionary、String
等都是值类型
。引用类型: 如
class类型、closure闭包、函数
等为引用类型
区别
值类型:
传递和存储
是一个副本
,使用过程中不会影响源数据
,存储在栈区
,访问一次拿到数据引用类型:
传递和存储
是本身(内存地址)
,使用过程中会影响源数据
,存储在堆区
,访问两次拿到数据,栈区拿到指针地址
,指针地址到堆区拿到内存地址
什么是函数?
函数是
一个独立的代码块
,由名字、参数、返回值
组成。函数类型由
形式参数类型和返回类型
决定全局函数和内嵌函数时
特殊的闭包
函数是
引用类型
,存储在堆
区
什么是枚举?oc 与 swift 枚举有啥区别?
枚举
是一种数据类型
,只包含自定义的特定数据,值类型
,存储在栈区
OC
,枚举只支持整数型
,很鸡肋Swift
中枚举有很多功能:- 可以定义
成员类型、计算属性、类型属性(不能定义存储属性)、方法
- 可以定义
下标脚本
用于获取值
- 可以定义
初始化器
用于生成初始化值
- 可以定义
扩展增加默认实现的功能
- 可以定义
遵守协议(protocol)
来提供标准化功能
。 - 可以定义
嵌套枚举、递归枚举
- 可以定义
泛型的作用?
解决代码的复用性和抽象能力
Swift 中的 KVC 和 KVO
- KVC:要继承
NSObject
- KVO:由于
Swift
为了效率, 默认禁用了动态派发
, 因此Swift
要实现KVO
, 除了要继承自NSObject
外还要将观测的对象标记为dynamic
(让swift
代码也能有Objective-C
中的动态机制)
什么是协议?作用?
- 协议
规定了用来实现某一特定功能所必须的属性和方法
,这个属性指实例属性或类属性
,而不用指定是存储属性或计算属性
类、结构体、枚举
都可以遵循协议,提供具体的实现
来完成协议定义的属性和方法
swift 协议 和 oc 协议有啥区别?
swift 协议:
- 协议可以定义
属性和方法
, 定义属性
必须明确是可读的/可读可写 { set get }
- 协议可以定义
继承
其他协议 - 协议可以定义
扩展协议
- 协议可以定义
指定初始化器或便捷初始化器
- 协议可以用于
类、结构体、枚举
oc 协议:
- 受限于委托代理,多用于不同类之间的传值和回调
什么是扩展?作用?
1、扩展可以向一个已有的 类型、结构体、枚举、协议
添加新的功能
2、作用:
- 可以添加
计算型实例属性
和计算型类型属性
。 - 可以添加
实例方法和类型方法
- 可以添加
新的初始化器
- 可以添加
下标脚本
- 可以使现有的
类型遵循某协议
- 定义和使用
新内嵌类型
- 扩展
可以向一个类型添加新的方法
,但是不能重写已有的方法
使用注意:
- 不可以添加
存储属性
和属性观察器
associatedtype 关键字作用?
- 关联类型:给
协议
中用到的某个类型
起一个占位符名称
final 关键字作用?
final
:只能用于类
中,final
声明的类
不能被继承,final
声明的属性、方法不能被重写
。
inout 关键字作用?
- inout: 输入输出形式参数,用来
修改形式参数的值,函数结束后仍然生效
,因为函数的参数是值类型
@objc 关键字作用?
- @objc:用于
OC
访问swift
,类
需要继承NSObject
dynamic 关键字作用?
dynamic :让方法具有动态性,用于
method-swizzling
, 需要类
继承NSObject
@objc + dynamic :用来实现消息发送
mutaing 关键字作用?
- mutaing:结构体内嵌函数修改存储属性
dynamic framework 和 static framework 的区别是什么?
静态库和动态库, 静态库是每一个程序单独打包一份, 而动态库则是多个程序之间共享.
静态库和动态库是相对编译期和运行期的:静态库在程序编译时会被链接到目标代码中,程序运行时将不再更改静态库;而
动态库
在程序编译时并不会被链接到目标代码中,只是在程序运行时
才被载入。静态库在链接时,会被完整的
复制
到可执行文件中,如果多个App都使用了同一个静态库,那么每个App都会拷贝一份,缺点是浪费内存
.动态库不会复制,
只有一份
,程序运行时动态加载到内存中,系统只会加载一次,多个程序共用一份,节约了内存
.
常用的三方框架
- Alamofire:网络加载
- HandyJson:JSON数据解析
- RxSwift:响应式编程
- Snapkit:自动布局
- MZRefresh:刷新加载
- Kingfisher:网络图片加载和缓存
- Post title:iOS面试题:Swift
- Post author:张建
- Create time:2023-03-01 16:57:50
- Post link:https://redefine.ohevan.com/2023/03/01/面试题/Swift面试题:总结/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.