Struct和Class的区别
- Struct不支持继承、Class支持继承
- Struct是值类型,Class是引用类型
- Struct无法修改自身属性值,函数需要添加mutating关键字
- Struct初始化方法是基于属性的
- Struct不需要deinit方法,因为值类型不关心引用计数,Class需要deinit方法。
结构体不可以继承
Swift值类型的写时复制
只有当一个结构体发生了写入行为时才会有复制行为。
在结构体内部用一个引用类型来存储实际的数据,在不进行写入操作的普通传递过程中,都是将内部的reference的应用计数+1,在进行写入操作时,对内部的reference做一次copy操作用来存储新的数据,防止和之前的reference产生意外的数据共享。
swift中提供该
[isKnownUniquelyReferenced]
函数,他能检查一个类的实例是不是唯一的引用,如果是,我们就不需要对结构体实例进行复制,如果不是,说明对象被不同的结构体共享,这时对它进行更改就需要进行复制。
defer的用法
使用defer代码块来表示在函数返回前,函数中最后执行的代码。无论函数是否会抛出错误,这段代码都将执行。
defer 语句块中的代码, 会在当前作用域结束前调用。每当一个作用域结束就进行该作用域defer执行。
1 | func doSomethingFile{ |
static和class的区别
在Swift中static和class都表示“类型范围作用域”的关键字。
在所有类型中(class、static、enum)中,我们可以使用static来描述类型作用域。class是专门用于修饰class类型的
。
static可以修饰属性和方法
- 所修饰的属性和方法不能够被重写。
- static修饰的类方法和属性包含了final关键字的特性,重写会报错
class修饰方法和计算属性
- 我们同样可以使用class修饰方法和计算属性,但是不能够修饰存储属性。
- 类方法和计算属性是可以被重写的,可以使用class关键字也可以是static
mutating关键字的使用?
类是引用类型,而结构和枚举是值类型。默认情况下,不能在其实例方法中修改值类型的属性。为了修改值类型的属性,必须在实例方法中使用mutating关键字。使用此关键字,您的方法将能够更改属性的值,并在方法实现结束时将其写回到原始结构
闭包是引用类型吗?
闭包是引用类型。如果一个闭包被分配给一个变量,这个变量复制给另一个变量,那么他们引用的是同一个闭包,他们的捕捉列表也会被复制。
闭包和函数是引用类型,将函数或闭包赋值给一个常量还是变量,实际上都是将常量或变量的值设置为对应函数或闭包的引用。
逃逸闭包
当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。
1 | func request(result:@escaping((String)->())){ |
逃逸闭包的生命周期是长于函数的。
逃逸闭包的生命周期:
- 闭包作为参数传递给函数;
- 退出函数;
- 闭包被调用,闭包生命周期结束。
非逃逸闭包, 永远不会离开一个函数的局部作用域的闭包就是非逃逸闭包。
1 | func player(complete:(Bool)->()){ |
非逃逸闭包的生命周期:
- 闭包作为参数传给函数;
- 函数中运行改闭包;
- 退出函数。
为什么要分逃逸闭包和非逃逸闭包
为了管理内存,闭包会强引用它捕获的所有对象,比如你在闭包中访问了当前控制器的属性、函数,编译器会要求你在闭包中显示 self 的引用,这样闭包会持有当前对象,容易导致循环引用。
而对于非逃逸闭包:
非逃逸闭包不会产生循环引用,它会在函数作用域内释放,编译器可以保证在函数结束时闭包会释放它捕获的所有对象。
使用非逃逸闭包可以使编译器应用更多强有力的性能优化,例如,当明确了一个闭包的生命周期的话,就可以省去一些保留(retain)和释放(release)的调用。
非逃逸闭包它的上下文的内存可以保存在栈上而不是堆上。
String 与 NSString 区别?
根本区别: String 是结构体, NSString 是类
怎么获取一个 String 的长度?
Objc 中读取 NSString 长度使用的是 .length,length返回的是基于 UTF-16 的长度
在 Swift 中读取 String 的长度,通常使用的是 count,而 count 本身返回的是 characters.count,只是 Unicode 字符个数。这两者的区别在纯文本中看不出来,但是包含 Emoji 的时候就十分明显了
举个例子:“😆😆😆😆😆😆”,用 Objc 的 length 读取返回的是12,而用 Swift 的 count 读取返回的是6,这在做一些富文本插入操作时,得到的结果绝不会是你想要的。
Swift 有专门的 utf16.count 来对应 NSString 的 .length,在使用的时候只需要 string.utf16.count就可以得到与 Objc 中 length 相同的结果
如何截取 String 的某段字符串
需要使用 String.Index 来确定要截取的范围,substring:to , substring:from, substring:with.
1 |
|
throws 和 rethrows 的用法与作用
throws 用在函数上, 表示这个函数会抛出错误.
有两种情况会抛出错误,
一种是直接使用 throw 抛出,
另一种是调用其他抛出异常的函数时, 直接使用 try xx 没有处理异常.
如
1 | enum DivideError: Error { |
rethrows 与 throws 类似, 不过只适用于参数中有函数, 且函数会抛出异常的情况, rethrows 可以用 throws 替换, 反过来不行
1 | func processNumber(a: Double, b: Double, functionC: (Double, Double) throws -> Double) rethrows -> Double { |
try try? try! 的区别
这两个都用于处理可抛出异常的函数, 使用这两个关键字可以不用写 do catch
- try 出现异常处理异常
- try? 不处理异常,返回一个可选值类型,出现异常返回nil
- try! 不让异常继续传播,一旦出现异常程序停止,类似NSAssert()
associatedtype的作用:
简单来说就是 protocol 使用的泛型
什么时候使用 final?
final关键字可以用在class ,func和var前面进行修饰,表示不允许对内容进行继承或者重写操作。 给一段代码加上final 就意味着你告诉编译器这段代码不会再被修改。
public 和 open 的区别
这两个都用于在模块中声明需要对外界暴露的函数, 区别在于, public 修饰的类, 在模块外无法继承,
而 open 则可以任意继承, 公开度来说, public < open
声明一个只有一个参数没有返回值闭包的别名
没有返回值也就是返回值为 Void
1 | typealias SomeClosuerType = (String) -> (Void) |
Self 的使用场景
Self 通常在协议中使用, 用来表示实现者或者实现者的子类类型.
如, 定义一个复制的协议
1 | protocol CopyProtocol { |
type(of:) vs .self
通过 type(of:) 和 .self都可以获得元类型的值。那么这两种方式的区别是什么呢?
1 | let instanceMetaType: String.Type = type(of: "string") |
self 取到的是静态的元类型,声明的时候是什么类型就是什么类型。type(of:) 取的是运行时候的元类型,也就是这个实例 的类型。
dynamic 的作用
由于 swift 是一个静态语言, 所以没有 Objective-C 中的消息发送这些动态机制, dynamic 的作用就是让 swift 代码也能有 Objective-C 中的动态机制, 常用的地方就是 KVO 了, 如果要监控一个属性, 则必须要标记为 dynamic
什么时候使用 @objc
@objc 用途是为了在 Objective-C 和 Swift 混编的时候, 能够正常调用 Swift 代码. 可以用于修饰类, 协议, 方法, 属性。
常用的地方是在定义 delegate 协议中, 会将协议中的部分方法声明为可选方法, 需要用到@objc
1 | @objc protocol OptionalProtocol { |
Optional(可选型) 是用什么实现的
Optional 是一个泛型枚举
大致定义如下:
1 | enum Optional<Wrapped> { |
除了使用 let someValue: Int? = nil 之外, 还可以使用let optional1: Optional
下面的代码会不会崩溃,说出原因
1 | var mutableArray = [1,2,3] |
不会, 原理不清楚, 就算是把 removeLast(), 换成 removeAll() ,这个循环也会执行count次, 估计是在一开始, for in 就对 mutableArray 进行了一次值捕获,
而 Array 是一个值类型 , removeLast() 并不能修改捕获的值。
给集合中元素是字符串的类型增加一个扩展方法,应该怎么声明
使用 where 子句, 限制 Element 为 String
1 | extension Array where Element == String { |