private和fileprivate的区别
swift 面试题
https://blog.csdn.net/shihuboke/article/details/106388320
swift 与oC 的区别
//www.greatytc.com/p/158d65bc281e
- 结构体调用方法时,是直接call地址,而类实例调用方法时,则是通过偏移找到方法在vtable的位置,然后再call调用
- 经过objc dynamic修饰的,方法调用objc_msgSend
swift onower 和weak的区别,onower什么情况下用
weak、unowned 都能解决循环引用的问题
unowned 要比weak 少一些性能消耗
在生命周期中可能会变为 nil 的使用 weak,初始化赋值后再也不会变为 nil 的使用 unowned
相同点: 引用对象的引用计数都不会加一,都不会对引用对象产生强引用
不同点:weak的对象,在block块内再次获取的时候是可选的,可能为nil,调用属性或者方法需要加上?或者强制解析!,但是强制解析在对象已经被释放了时肯定会造成强解错误,导致程序崩溃
unower的对象,在block块内再次获取的时候依然是对象本身,非可选,因为一定保证在block块内再次获取的时候对象依然存在,不然调用属性或者方法肯定会造成导致程序崩溃
另外,你还可以利用【生命周期】的长短去理解,即分别在什么场景下使用unowned和weak:
unowned所在的block的生命周期务必要比unowned修饰对象的生命周期短,即block一旦销毁了,也就不会再调用了,也就不存在修饰对象的引用问题了。
weak所在的block可能要比weak修饰对象的生命周期长,block被调用时,修饰对象可能已经释放掉了,此时通过修饰对象?去调用也就不会引发问题,保证程序正常运行。
什么时候使用 weak和unowned
- Weak和unowned引用都不会增加引用计数,它们都能用于解除引用循环。
- 在引用对象的生命周期内,如果它可能为nil,那么就用weak引用。反之,当你知道引用对象在初始化后永远都不会为nil就用unowned.
进行判断使用class_深入理解Swift中的Class和Struct
Swich
- Switch 默认可以不写break,并不会贯穿到后面的条件
- 使用fallthrough可以实现贯穿效果
- switch必须要保证能处理所有情况
- case、default后面至少要有一条语句,如果不想做任何事,加个break即可
- switch也支持Character、String类型
- Case 后面的条件也支持元组,区间,复合条件,值绑定
- public func print(_ items: Any..., separator: String = " ", terminator: String = "\n")
inout
- 可以用inout定义一个输入输出参数:可以在函数内部修改外部实参的值,func swapValues(_ v1: inout Int, _ v2: inout Int) {}
函数重载
- 函数 个数 标签 类型不同(返回值类型不同不叫重载)
- 默认参数与函数重载一起用产生歧义的时候不报错(C++ 报错)
高阶函数,返回值是函数类型的是高阶函数
- 每一个函数都是有类型的,函数类型由形式参数类型、返回值类型组成
- 函数类型作为函数的返回值,
- 函数类型作为函数参数
- 将一个接受多参数的函数变换为一系列只接受单个参数的函数,叫做柯里化
-
像Array这样支持map运算的类型,称为函子(Functor)
内敛函数
- 如果开启了编译器优化(Release模式默认会开启优化),编译器会自动将某些函数变成内联函数
- 将函数调用展开成函数体
- 有些函数不被自动内敛(函数体较长,包含递归)
- 永远不会被内联(即使开启了编译器优化) @inline(never) func test() {}
- 被内联(开启了编译器优化即使过长也被内敛) @inline(__always) func test() {}
typealias
typealias用来给类型起别名
枚举
枚举有扩展
-
关联值 将枚举的成员值跟其他类型的值关联存储在一起
原始值 注意:原始值不占用枚举变量的内存,隐式原始值如果枚举的原始值类型是Int、String,Swift会自动分配原始值,int默认0,1,String就是同名称的字符串
空合并运算符 ??
- a ?? b
- a 是可选项 ,b 是可选项 或者 不是可选项
- b 跟 a 的存储类型必须相同
- 如果 a 不为nil,就返回 a
- 如果 a 为nil,就返回 b
- 如果 b 不是可选项,返回 a 时会自动解包
结构体&类
- 结构体,编译器会自动生成可以传入成员值的初始化方法,如果在定义结构体的时候自定义了初始化方法,那么编译器不会自动生成;
- 类,编译器不会自动生成以传入成员值的初始化方法,如果定义类的时候,所有成员变量定义了初始值,那么编译器会自动生成无参的初始化方法
- 结构体是值类型(枚举也是值类型),类是引用类型(指针类型)
结构体定义的成员变量的值 - 类是指针引用,栈上的指针引用堆上的实例对象;结构体是值引用(值拷贝),实例内存就在栈上
属性
-
存储属性 :存储在实例的内存中,结构体和类可以定义存储属性,
- 存储实例属性:可以通过实例访问,存储在每个实例的内存中
- 存储类型属性:通过类型访问,整个程序运行过程只分配一块内存
-
计算属性(类似于函数,有get set 方法,不占用实例内存,结构体和类枚举可以定义计算属性)
- 计算实例属性:可以通过实例访问,存储在每个实例的内存中
-
计算类型属性:通过类型访问,只分配一块内存
inout的本质就是引用传递(地址传递)
动态类型语言
- 运行时才做数据类型检查,在编译阶段不给变量设置任何数据类型,在第一次给变量赋值的时候,内部会记录下数据类型
静态类型语言
- 编译时就开始做数据类型检查,变量声明的就得设置数据类型,使用之前也得声明数据类型
mutating
- 结构体和枚举是值类型,默认情况下,值类型的属性不能被自身的实例方法修改
- 在func关键字前加mutating可以允许这种修改行为
下标(subscript)
n 使用subscript可以给任意类型(枚举、结构体、类)增加下标功能,有些地方也翻译为:下标脚本,本质是方法,可以没有set方法,必须要get方法
继承
- 值类型(枚举、结构体)不支持继承,只有类支持继承
- 子类可以重写父类的下标、方法、属性,重写必须加上override关键字
- 被class修饰的类型方法、下标,计算类型属性,允许被子类重写
- 被static修饰的类型方法、下标,类型属性,不允许被子类重写
- 子类可以将父类的属性(存储、计算)重写为计算属性
- 子类不可以将父类属性重写为存储属性
- 只能重写var属性,不能重写let属性
- 子类重写后的属性权限 不能小于 父类属性的权限
- 被final修饰的方法、下标、属性,禁止被重写
- 被final修饰的类,禁止被继承
Any、AnyObject
- Any:可以代表任意类型(枚举、结构体、类,也包括函数类型)
- pAnyObject:可以代表任意类类型(在协议后面写上: AnyObject代表只有类能遵守这个协议),在协议后面写上: class也代表只有类能遵守这个协议
错误类型
- Swift中可以通过Error协议自定义运行时的错误信息
- 函数内部可以通过throw 抛出自定义errow
- 可以使用do-catch捕捉Error
- defer语句:用来定义以任何方式(抛错误、return等)离开代码块前必须要执行的代码
- defer语句将延迟至当前作用域结束之前执行
- defer语句将延迟至当前作用域结束之前执行
- assert(断言)
- 如果遇到严重问题,希望结束程序运行时,可以直接使用fatalError函数抛出错误(这是无法通过do-catch捕捉的错误)
- 使用了fatalError函数,就不需要再写return, 在某些不得不实现、但不希望别人调用的方法,可以考虑内部使用fatalError函数
- 可以使用do 实现局部作用域
闭包&自动闭包
- 如果将一个很长的闭包表达式作为函数的最后一个实参,使用尾随闭包可以增强函数的可读性
- 尾随闭包是一个被书写在函数调用括号(后面)的闭包表达式
逃逸闭包
- 逃逸闭包: 闭包作为函数的参数传递时,在函数体结束之后调用,就说闭包逃避了函数的作用域,这个闭包是逃逸型的闭包,使用@escaping来标注, 逃逸闭包一般会在多线程中使用
- 非逃逸型的闭包:在函数体结束前被调用,闭包是非逃逸型的闭包。
协议
- 只有将协议中的实例方法标记为mutating,才允许结构体、枚举的具体实现修改自身成员变量
- 类在实现方法时不用加mutating,枚举、结构体才需要加mutating
- 协议中还可以定义初始化器init ,非final类实现时必须加上required
- 如果从协议实现的初始化器,刚好是重写了父类的指定初始化器 ,那么实现的时候这个初始化必须同时加required override
- 一个协议可以继承其他协议
- 枚举,类,类都可以遵守协议
- 协议可以添加扩展
- 协议扩展可以为遵守协议的类型添加实现,但它不能使协议从另一个协议扩展或继承。协议继承始终在协议声明本身指定。
- 如果一个类型已经符合协议的所有要求,但是还未声明采用了该协议,则可以让它采用一个空扩展的协议:
- is用来判断是否为某种类型,as用来做强制类型转换
- 枚举结构体协议类都可以加扩展