本文复制 https://www.jianshu.com/p/23d99f434281
class 和 struct 的区别
class 为类,struct 为结构体,类是引用类型,结构体是值类型。结构体不可以继承
不通过继承,代码复用(共享)的方式有哪些
扩展,全局函数
Set 独有的方法有哪些?
1 | //定义一个set |
实现一个 min 函数,返回两个元素较小的元素
1 | func myMin<T: Comparable>(_a: T, _ b: T) -> T { |
map、filter、reduce 的作用
map 用于映射,可以将一个列表转换为另一个列表
1 | [1, 2, 3].map{"\($0)"} //数字数组转换为字符串数组 |
filter 用于过滤,可以筛选出想要的元素
1 | [1, 2, 3].filter{$0 %2 == 0} //筛选偶数 |
reduce 合并
1 | [1, 2, 3].reduce(""){$0 + "\($1)"} //转换为字符串拼接 |
map 与 flatmap 的区别
flatmap 有两个实现函数实现
1 | public func flatMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult ?) -> rethrows -> [ElementOfResult] |
另一个实现
1 | public func flatMap<SegmentOfResult>(_ transform: (Element) throws ->SegmentOfResult) rethrows -> [SegmentOfResult.Iterator.Element] where SegmentOfResult : Sequence |
什么事copy on write时候
写时复制,指的是swift中的值类型,并不会一开始赋值的时候就去复制,只有再需要修改的时候,才去复制。
这里有相关说明
http://www.jianshu.com/p/7e8ba0659646
如何获取当前代码的函数名和行号
#file
用于获取当前文件文件名#line
用于获取当前行号#column
用于获取当前编号function
用于获取当前函数名
以上这些都是特殊的字面量,多用于调试输出日志。
具体app文档
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html
这里有中文翻译
http://wiki.jikexueyuan.com/project/swift/chapter3/04_Expressions.html
如何声明一个只能被类conform的protocol
申明协议的时候,加一个class即可:如
1 | protocol SomeClassProtocl : class { |
guard使用场景
guard和if类似,不同的是,guard总是有一个else语句,如果表达是假或绑定失败的时候,就会执行else语句,而在else语句中一定要停止函数调用
1 | guard 1+1 == 2 ? else { |
defer使用场景
defer语句块使用中的代码,会在当前作用域结束前调用,常用场景如异常退出后,关闭数据库连接
1 | func someQuery() -> ([Result], [Result]){ |
String 与 NSString 的关系与区别
String 是结构体,值类型,NSStirng 是类,引用类型
NSString 与 String之间可以随意转换
1 | let someString = "123" |
怎么获取一个 String 的长度
不考虑编码,只是想知道字符的数量,用 characters.count
1 | "hello".count |
如何截取 String 的某段字符串
swift中,有三个取字符串函数
substring:to, substring:from, substring:with
1 | let simpleString = "Hello,world" |
throws 和 rethrows 的用法与作用
throws 用在函数上,表示这个函数会抛出异常
有两种情况下会抛出错误,一种是直接使用throw抛出,另一种是调用其他抛出异常的函数时,直接使用try xx没有处理异常。如
1 | enum DivideError: Error { |
rethrows 与 throws 类似,不过只适用于参数中有函数,且函数会抛出异常的情况下,rethrows 可以用throws替换,反过来不行.如
1 | func processNumber(a: Double, b: Double, function: (Double, Double) throws -> Double) rethrows -> Double { |
try? 和 try! 是什么意思
这两个都用于处理可抛出异常的函数,使用这两个关键字不用写 do catch,区别在于 try?在用于处理可抛出异常函数时,如果函数抛出异常,则可以返回nil,否则返回函数值的可选值,如:
1 | print(try? divide(2, 1)) |
而try! 则在函数抛出异常的时候奔溃。否则则返回函数的返回值。如
1 | print(try! divide(2, 1)) |
associatedtype 的作用
简单来说就是protocol 使用的泛型
例如定义一个列表协议
1 | protocol ListProtocol{ |
实现协议的时候,可以使用typealias 指定特定的类型,也可以自动推断,如
1 | class IntList: ListProtocol { |
使用泛型也可以
1 | class AnyList<T>: ListProtocol{ |
可以使用where字句限定Element类型,如:
1 | extension ListProtocol where Element == Int { |
什么时候使用 final
final用于限制继承和重写,如果只是需要在某一个属性前加一个final。如果需要限制整个类无法被继承,那么可用用类名之前加一个final
public 和 open 的区别
这两个都用于模块声明需要对外界暴露的函数,区别在于,public 修饰的类,在模块外无法被继承,而open则可以任意继承,公开度来说,open>public
声明一个只有一个参数没有返回值闭包的别名
1 | typealias SomeClosuerType = (Stirng) -> () |
Self 的使用场景
self 通常在协议中使用,用来表明实现者或者实现者的子类类型
1 | protocol CopyProtocol { |
如果是结构体去实现,要将Self转换为具体类型
1 | struct SomeStruct : CopyProtocol{ |
如果是类去实现,则有点复杂,需要有一个required初始化方法,具体可以看这里
1 | class SomeCopyableClass : CopyProtocol { |
dynamic的作用
由于swift是一个静态语言,所以没有Objective-C中的消息发送这些动态机制,dynamic的作用就是让swift代码也能有Object-C中的动态机制,常用的方法就是KVO了,如果要监控这一个属性,则必须要标记dynamic。可以参考这篇文字http://www.jianshu.com/p/ae26100b9edf
什么时候使用 @objc
@objc 用途是为了在Objective-C 和Swift混编的时候,能够正常的调用Swift代码,可以修饰类,协议,方法,属性。
常用的地方是在定义deleagte 协议中,会将协议中部分方法申明为可选方法,需要用到 @objc
1 | @objc protocol OptionalProtocol { |
Optional(可选型) 是用什么实现的
Optional 是一个泛型枚举,大致定义如下
1 | enum Optional<Wrapped> { |
如何自定义下标获取
实现subscript即可,如
1 | extension AnyList { |
?? 的作用
可选类型的默认值,但可选类型为nil的时候,会返回后面的值,如let someValue = optional1 ?? 0
lazy 的作用
懒加载,当属性要使用的时候,才去完成初始化。如
1 | class LazyClass { |
一个类型表示选项,可以同时表示有几个选项选中(类似UIViewAnimationOptions ),用什么类型表示
需要实现自OptionSet,一般使用struct实现,由于OptionSet要求有一不可失败的构造器init(rawValue:),而枚举无法做到这一点(枚举的原始值构造器是失败的,而且有些组合值,是没有办法用一个枚举值表示的)
1 | struct SomeOption: OptionSet{ |
inout 的作用
输入输出参数
Error 如果要兼容 NSError 需要做什么操作
其实直接转换就可以,例如:SomeError.someError as NSError 但是这样没有错误码,描述等等,如果想和NSError一样有这些东西,只需要实现LocalizedError 和 CustomNSError协议,有些方法有默认实现,可以略过。如:
1 | enum SomeError : Error , LocalizedError, CustomNSError { |
下面的代码都用了哪些语法糖
[1, 2, 3].map{ $0 * 2 }
[1, 2, 3]使用了Array实现的ExpressibleByArrayLiteral 协议,用于接收数组的字面值。
map{***} 使用了闭包作为最后一个参数时,可以直接写在调用后面,而且,如果是唯一参数的话,圆括号也可以省略。
闭包没有声明函数参数,返回值类型,数量,依靠的是闭包类型的自动推断。
闭包中语句只有一句时,自动将这一句的结果作为返回值
$0 没有声明参数列表的时候,第一个参数名称为$0,后续参数以此类推
什么是高阶函数
一个函数如果可以以某一个函数作为参数,或者返回值,那么这个函数就称之为高阶函数,如 map, reduce, filter
如何解决引用循环
- 转换为值类型,只有类会存在引用循环,所以如果能不用类,是可以解决引用循环的。
- deleagte 使用 weak属性
- 闭包中,对有可能发生循环引用的对象,使用weak或者unowned修饰
下面的代码会不会崩溃,说出原因
1 | var mutableArray = [1, 2, 3] |
不会,原理不清楚,就算是把removeLast(),换成removeAll(),这个循环也会执行三次,估计是一开始,for in就对mutalbeArray进行了一次值捕获,而Array是一个值类型,removeLast() 并不能修改捕获值
给集合中元素是字符串的类型增加一个扩展方法,应该怎么声明
使用where子句,限制 Element为String
1 | 指定Array集合元素类型为String的扩展。如果Array集合的元素非String类型,扩展里的方法就不能使用 |
定义静态方法时关键字 static 和 class 有什么区别
static 定义的方法不可以被子类继承,class则可以
1 | class AnotherClass { |
一个Sequence的索引是不是一定从0开始
不一定,两个for in 并不能保证都是从0开始,且输出结果一致,官方文档如下
Repeated Access
The Sequence protocol makes no requirement on conforming types regarding
whether they will be destructively consumed by iteration. As a
consequence, don’t assume that multiple for-in loops on a sequence
will either resume iteration or restart from the beginning:
1
2
3
4
5
6
7
8 > for element in sequence {
> if ... some condition { break }
> }
>
> for element in sequence {
> // No defined behavior
> }
>
举例
1 | class Countdown: Sequence, InteratorProtocol { |
最后输出结果是
1 | begin for in 1 |
很明显,第二次没有输出任何结果,原因就是第二次for in的时候,并没有将 count 重值。
数组都实现了哪些协议
mutableCollection ,实现了可修改的数组,如 a[1] = 2
ExpressibleByArrayLiteral 实现了数组可一次从[1,2,3]这种字面初始化的能力
如何自定义模式匹配
这部分不太懂,贴个链接吧 http://swifter.tips/pattern-match/
autoclosure 的作用
自动闭包,会自动将某一个表达式封装为闭包,如
1 | func autoClosureFunction(_ closure: @autoclosure () -> Int){ |
详细可参考http://swifter.tips/autoclosure/
编译选项 whole module optmization 优化了什么
编译器可以跨文件优化编译代码,不局限于一个文件
http://www.jianshu.com/p/8dbf2bb05a1c
下面代码中mutating的作用是什么
1 | struct Person{ |
让不可变对象无法访问属性name
如何让自定义对象支持字面量初始化
有几个协议,分别是ExpresssibleByArrayLiteral
可以由数组形式初始化ExpressibleByDictionaryLiteral
可以由字典形式初始化ExpressibleByNilLiteral
可以由nil值初始化ExpressibleByIntegerLiteral
可以由整数型初始化ExpressibleByFloatLiteral
可以由浮动数初始化ExpressibleByBooleanLiteral
可以由布尔值初始化
dynamic framework 和 static framework 的区别是什么
静态库是每一个程序单独打包一份,而动态库则是多个程序之间共享