原题的链接:http://www.jianshu.com/p/7c7f4b4e4efe
1. class 和 struct 的区别
一个引用类型,一个值类型
2. 不通过继承,代码复用(共享)的方式有哪些
在swift 文件里直接写方法,相当于一个全局函数。
extension 给类直接扩展方法。
3. Set 独有的方法有哪些?
不会出现重复的值。
里面的元素必须时相同的类型。
4. 实现一个 min 函数,返回两个元素较小的元素
func min(_ a : T , b : T) -> T {
return a < b ? a : b
}
5. map、filter、reduce 的作用
map : 映射 , 将一个元素根据某个函数 映射 成另一个元素(可以是同类型,也可以是不同类型)
filter : 过滤 , 将一个元素传入闭包中,如果返回的是false , 就过滤掉
reduce :先映射后融合(这样说容易理解) , 将数组中的所有元素映射融合在一起。举个例子:
求所有人的钱的总和,这里钱是字符串表示的
struct Person {
let name : String
let money : String
}
let a = Person(name: "小王", money: "5.0")
let b = Person(name: "小李", money: "7.1")
let c = Person(name: "小张", money: "3.22")
let sumMoney = [a , b , c].reduce(0) {
return $0 + ($1.money as NSString).doubleValue
}
print(sumMoney)
//15.32
6. map 与 flatmap 的区别
map不能将元素映射成可选类型,flatmap可以
7. 什么是 copy on write
百度
8. 如何获取当前代码的函数名和行号
函数名#functio 行号#line 文件名#file
9. 如何声明一个只能被类 conform 的 protocol
protocol OnlyClassProtocol : class {
}
10. guard 使用场景
相当于
if !(...) {
return
}
可以理解为拦截,凡是不满足 guard 后面条件的,都不会再执行下面的代码。
我一般用来解包 。 不能解包的, 就不能执行下面的代码
11. defer 使用场景
在一对花括号 : { } 里 使用defer ,这个defer 里面的内容将会在结束 {} 前(or 后?) 被执行
11. String 与 NSString 的关系与区别
能够互相转换,一个值类型,一个引用类型
12. 怎么获取一个 String 的长度
print( "abcdefg".characters.count )
//7
("abcdefg" as NSString).length //这个要算作NSString的获取长度的方法
13. throws 和 rethrows 的用法与作用
throws 声明在函数的末尾,表示这个函数会抛出 Error的子类.
rethrows 再传入throws的闭包时,这个函数返回用rethrows
14. try? 和 try!是什么意思
try! 强制抛出错误,有错误就会崩溃
try? 抛出错误,没错误不会崩溃直接返回
try :
如果不用do catch , 就会编译报错
如果函数后面加上 throws , 将错误传递下去. 即使不用都do catch 编译也不会报错。 但是调用throwfun2()
还是要使用do catch
14. associatedtype 的作用
相当于protocol的范型
protocol Animal {
associatedtype AnimalType : Comparable
}
extension Animal {
typealias AnimalType = Self
}
13. 什么时候使用 final
不允许class 被继承
不允许函数被重写
14. public 和 open 的区别
没用过 百度吧
15. 声明一个只有一个参数没有返回值闭包的别名
typealias NoReturn = (String) -> Void
16. Self 的使用场景
表示自己本身的类型,见14的例子
17. dynamic 的作用
动态化。用的少
18. 什么时候使用 @objc
与oc交互。
19. Optional(可选型) 是用什么实现的
enum 和 重载符号 ?
20. 如何自定义下标获取
Array的文档
21. ?? 的作用
当 ?? 前面的值为nil 的时候就取 ??后面的值
22. lazy 的作用
只有属性被调用的时候才会执行lazy
如果直接给属性赋值
22. 一个类型表示选项,可以同时表示有几个选项选中(类似 UIViewAnimationOptions ),用什么类型表示
继承了OptionSet的struct , enum 。 class 没有试过,应该也可以
23. inout 的作用
改变函数外的值
24. Error 如果要兼容 NSError 需要做什么操作
不明白
25. 下面的代码都用了哪些语法糖 [1, 2, 3].map{ $0 * 2 }
用$0 捕获第一个参数。
只有一行代码的时候, 隐藏掉了 return 。
26. 什么是高阶函数
Curry化? 百度
27. 如何解决引用循环
weak unowned 关键字
28. 下面的代码会不会崩溃,说出原因
var mutableArray = [1,2,3]
for _ in mutableArray {
mutableArray.removeLast()
}
在原题主的评论里有了
29. 给集合中元素是字符串的类型增加一个扩展方法,应该怎么声明
参考文档的写法
报错了。
所以用了一个投机取巧的办法
30. 定义静态方法时关键字 static 和 class 有什么区别
struct 只能用static
class 的属性只能用 static , 其他地方都能随便用。
反正编译器会告诉你的
31. 一个 Sequence 的索引是不是一定从 0 开始?
不是。
ArraySlice是Sequence的子类,ArraySlice就不是
32. 数组都实现了哪些协议
翻文档?
class 为类, struct 为结构体, 类是引用类型, 结构体为值类型, 结构体不可以继承
扩展, 全局函数
// 定义一个 set
let setA: Set = [0,1, 2, 3, 4, 4]// {1, 2, 3, 4}, 顺序可能不一致, 同一个元素只有一个值
let setB: Set = [1, 3, 5, 7, 9]// {1, 3, 5, 7, 9}
// 取并集 A | B
let setUnion = setA.union(setB)// {0,1, 2, 3, 4, 5, 7, 9}
// 取交集 A & B
let setIntersect = setA.intersection(setB)// {1, 3}
// 取差集 A - B
let setRevers = setA.subtracting(setB) // {0,2, 4}
// 取对称差集, A XOR B = A - B | B - A
let setXor = setA.symmetricDifference(setB) //{0,2, 4, 5, 7, 9}
func getMin(_ a: T, _ b: T) -> T {
return a < b ? a : b
}
getMin(1, 2)
具体请参看我的博客 Swift 的高阶函数,map、flatMap、filter、reduce
map 函数 -- 对数组中的每一个对象做一次运算
let stringArray = ["Objective-C", "Swift", "Python", "HTML5", "C",""]
let resultAry = stringArray.map { (element) -> Int? in
if element.length > 0 {
return element.length
}else{
return nil
}
}
print(resultAry)
//[Optional(11), Optional(5), Optional(6), Optional(5), Optional(1), nil]
fiatMap 函数 -- 也是对每个对象做一次运算,但是有区别
区别1 不会返回 nil ,会把 optional 类型解包
let stringArray = ["Objective-C", "Swift", "Python", "HTML5", "C",""]
let resultAry = stringArray.flatMap { (element) -> Int? in
if element.length > 0 {
return element.length
}else{
return nil
}
}
print(resultAry)
//[11, 5, 6, 5, 1]
区别2 会把N 维数组变成成一个 1维 数组 返回
let stringArray = [["Objective-C", "Swift"], ["Python", "HTML5", "C",""]]
let resultAry = stringArray.map { $0 }
print(resultAry)
//[["Objective-C", "Swift"], ["Python", "HTML5", "C", ""]]
//flatMap
let stringArray = [["Objective-C", "Swift"], ["Python", "HTML5", "C",""]]
let resultAry = stringArray.flatMap { $0 }
print(resultAry)
//["Objective-C", "Swift", "Python", "HTML5", "C", ""]
filter 过滤,数组中的元素按照 闭包里面的规则过滤
let stringArray = ["Objective-C", "Swift", "Python", "HTML5", "C",""]
let resultAry = stringArray.filter { (element) -> Bool in
//元素长度大于5的 取出
return element.length >= 5
}
print(resultAry)
//["Objective-C", "Swift", "Python", "HTML5"]
reduce 计算,按顺序对数组中的元素进行操作,然后记录操作的值再进行下一步相同的操作,可以想象成累加。
let stringArray = ["Objective-C", "Swift", "Python", "HTML5", "C",""]
let resultStr = stringArray.reduce("Hi , I'm PierceDark,") { (element1, element2) -> String in
return element1 + " ," + element2
}
print(resultStr)
//Hi , I'm PierceDark, ,Objective-C ,Swift ,Python ,HTML5 ,C ,
写时复制, 指的是 swift 中的值类型, 并不会在一开始赋值的时候就去复制, 只有在需要修改的时候, 才去复制.
这里有详细的说明
《Advanced Swift》笔记:在Swift结构体中实现写时复制
#file
用于获取当前文件文件名#line
用于获取当前行号#column
用于获取当前列编号#function
用于获取当前函数名
加一个 class
protocol SomeClassProtocl: class {
func someFunction()
}
提前判断,如果表达式是假或者值绑定失败的时候, 会执行 else
语句, 且在 else
语句中一定要停止函数调用
使用场景如登录判断 账号密码 长度
defer
语句块中的代码, 会在当前作用域结束前调用, 常用场景如异常退出后, 关闭数据库连接 ,而且 defer
是先加入后执行
func someQuery() -> ([Result], [Result]){
let db = DBOpen("xxx")
defer {
db.close()
}
guard results1 = db.query("query1") else {
return nil
}
guard results2 = db.query("query2") else {
return nil
}
return (results1, results2)
}
String
是结构体,值类型,NSString
是类,引用类型。可以相互转换
"test".count
PS:Swift
截取子串真的不好用= = ,Swift4
不用substring:to
, substring:from
, substring:with
了,但还是很难用 .还不如转成NSString
再去截取。。
来自Stack Overflow
let newStr = str.substring(to: index) // Swift 3
let newStr = String(str[..
throws 用在函数上, 表示这个函数会抛出错误.
有两种情况会抛出错误, 一种是直接使用 throw 抛出, 另一种是调用其他抛出异常的函数时, 直接使用 try xx 没有处理异常.
如
enum DivideError: Error {
case EqualZeroError;
}
func divide(_ a: Double, _ b: Double) throws -> Double {
guard b != Double(0) else {
throw DivideError.EqualZeroError
}
return a / b
}
func split(pieces: Int) throws -> Double {
return try divide(1, Double(pieces))
}
rethrows 与 throws 类似, 不过只适用于参数中有函数, 且函数会抛出异常的情况, rethrows 可以用 throws 替换, 反过来不行
如
func processNumber(a: Double, b: Double, function: (Double, Double) throws -> Double) rethrows -> Double {
return try function(a, b)
}
这两个都用于处理可抛出异常的函数, 使用这两个关键字可以不用写 do catch.
区别在于, try? 在用于处理可抛出异常函数时, 如果函数抛出异常, 则返回 nil, 否则返回函数返回值的可选值
例子
print(try? divide(3, 1))
// Optional(3.0)
print(try? divide(3, 0))
// nil
而 try! 则在函数抛出异常的时候崩溃, 否则则返会函数返回值, 相当于(try? xxx)!, 如:
print(try! divide(3, 1))
// 2.0
print(try! divide(3, 0))
// 崩溃
这里来自:yww的这篇回答
protocol
使用的泛型
protocol ListProtcol {
associatedtype Element
func push(_ element:Element)
func pop(_ element:Element) -> Element?
}
实现协议的时候, 可以使用 typealias 指定为特定的类型, 也可以自动推断, 如
class IntList: ListProtcol {
typealias Element = Int // 使用 typealias 指定为 Int
var list = [Element]()
func push(_ element: Element) {
self.list.append(element)
}
func pop(_ element: Element) -> Element? {
return self.list.popLast()
}
}
class DoubleList: ListProtcol {
var list = [Double]()
func push(_ element: Double) {// 自动推断
self.list.append(element)
}
func pop(_ element: Double) -> Double? {
return self.list.popLast()
}
}
使用泛型也可以
class AnyList: ListProtcol {
var list = [T]()
func push(_ element: T) {
self.list.append(element)
}
func pop(_ element: T) -> T? {
return self.list.popLast()
}
}
可以使用 where 字句限定 Element 类型, 如:
extension ListProtcol where Element == Int {
func isInt() ->Bool {
return true
}
}
不能继承和重写,可用到 属性
/函数
/类
这两个都用于在模块中声明需要对外界暴露的函数, 区别在于, public
修饰的类, 在模块外无法继承, 而 open
则可以任意继承, 公开度来说, public < open
typealias SomeClosuerType = (String) -> ()
let someClosuer: SomeClosuerType = { (name: String) in
print("hello,", name)
}
这里来自:yww的这篇回答
Self 通常在协议中使用, 用来表示实现者或者实现者的子类类型
protocol CopyProtocol {
func copy() -> Self
}
如果是结构体去实现, 要将Self 换为具体的类型
struct SomeStruct: CopyProtocol {
let value: Int
func copySelf() -> SomeStruct {
return SomeStruct(value: self.value)
}
}
如果是类去实现, 则有点复杂, 需要有一个 required 初始化方法, 具体可以看 这里
class SomeCopyableClass: CopyProtocol {
func copySelf() -> Self {
return type(of: self).init()
}
required init(){}
}
动态化。因为Swift
是一个静态语言,如果需要有和OC
一样的动态化机制就需要加上dynamic
。
应用场景有Runtime
相关。参看Swift Runtime分析:还像OC Runtime一样吗?
Swift4
之后,继承NSObject
的Swift
类不会自动与 OC
交互了,属性前面需要加上@objc
另一个常用的地方为了在 Objective-C
和 Swift
混编的时候, 能够正常调用 Swift
代码. 可以用于修饰类, 协议, 方法, 属性.
常用的地方是在定义 delegate
协议中, 会将协议中的部分方法声明为可选方法, 需要用到
@objc protocol OptionalProtocol {
@objc optional func optionalFunc()
func normalFunc()
}
class OptionProtocolClass: OptionalProtocol {
func normalFunc() {
}
}
let someOptionalDelegate: OptionalProtocol = OptionProtocolClass()
someOptionalDelegate.optionalFunc?()
枚举
enum Optional {
case none
case some(Wrapped)
}
extension AnyList {
subscript(index: Int) -> T{
return self.list[index]
}
subscript(indexString: String) -> T?{
guard let index = Int(indexString) else {
return nil
}
return self.list[index]
}
}
当可选值为nil
时,输出后面给定的值
var test : String? = nil
print(test ?? "optional = nil")
//输出 optional = nil
用到的时候才初始化,懒加载
这里来自:yww的这篇回答
需要实现自OptionSet
, 一般使用 struct
实现. 由于 OptionSet
要求有一个不可失败的init(rawValue:)
构造器, 而 枚举无法做到这一点(枚举的原始值构造器是可失败的, 而且有些组合值, 是没办法用一个枚举值表示的)
struct SomeOption: OptionSet {
let rawValue: Int
static let option1 = SomeOption(rawValue: 1 << 0)
static let option2 = SomeOption(rawValue:1 << 1)
static let option3 = SomeOption(rawValue:1 << 2)
}
let options: SomeOption = [.option1, .option2]
输入输出参数,改变函数参数的值
这里来自:yww的这篇回答
其实直接转换就可以, 例如 SomeError.someError as NSError 但是这样没有错误码, 描述等等, 如果想和 NSError 一样有这些东西, 只需要实现 LocalizedError 和 CustomNSError 协议, 有些方法有默认实现, 可以略过, 如:
enum SomeError: Error, LocalizedError, CustomNSError {
case error1, error2
public var errorDescription: String? {
switch self {
case .error1:
return "error description error1"
case .error2:
return "error description error2"
}
}
var errorCode: Int {
switch self {
case .error1:
return 1
case .error2:
return 2
}
}
public static var errorDomain: String {
return "error domain SomeError"
}
public var errorUserInfo: [String : Any] {
switch self {
case .error1:
return ["info": "error1"]
case .error2:
return ["info": "error2"]
}
}
}
print(SomeError.error1 as NSError)
// Error Domain=error domain SomeError Code=1 "error description error1" UserInfo={info=error1}
[1, 2, 3].map{ $0 * 2 }
$0
代替一个函数如果可以以某一个函数作为参数, 或者是返回值, 那么这个函数就称之为高阶函数, 如 map, reduce, filter
var mutableArray = [1,2,3]
for _ in mutableArray {
mutableArray.removeLast()
}
跑了一遍不会。。可能因为数组里面元素是连续的储蓄位置,然后删除掉之后不会置nil
? 或者for in
的时候复制了?
extension Set where Element == String {
var isStringElement:Bool {
return true
}
}
static
不能被继承 ,class
可以
记得不是。但是想不起来例子。。。
这里参考yww的这篇回答
class Countdown: Sequence, IteratorProtocol {
var count: Int
init(count: Int) {
self.count = count
}
func next() -> Int? {
if count == 0 {
return nil
} else {
defer { count -= 1 }
return count
}
}
}
var countDown = Countdown(count: 5)
print("begin for in 1")
for c in countDown {
print(c)
}
print("end for in 1")
print("begin for in 2")
for c in countDown {
print(c)
}
print("end for in 2")
最后输出的结果是
begin for in 1
5
4
3
2
1
end for in 1
begin for in 2
end for in 2
很明显, 第二次没有输出任何结果, 原因就是在第二次for in 的时候, 并没有将count 重置.
MutableCollection
, 实现了可修改的数组, 如 a[1] = 2
ExpressibleByArrayLiteral
, 实现了数组可以从[1, 2, 3]
这种字面值初始化的能力
不太懂
http://swifter.tips/pattern-match/
自动闭包
http://swifter.tips/autoclosure/
编译器可以跨文件优化编译代码, 不局限于一个文件.
http://www.jianshu.com/p/8dbf2bb05a1c
struct Person {
var name: String {
mutating get {
return store
}
}
}
mutating
表示有可能修改这个结构体,所以只有var
的对象才可以调用
不太懂,参考yww的这篇回答
有几个协议, 分别是ExpressibleByArrayLiteral
可以由数组形式初始化ExpressibleByDictionaryLiteral
可以由字典形式初始化ExpressibleByNilLiteral
可以由nil 值初始化ExpressibleByIntegerLiteral
可以由整数值初始化ExpressibleByFloatLiteral
可以由浮点数初始化ExpressibleByBooleanLiteral
可以由布尔值初始化ExpressibleByUnicodeScalarLiteral
ExpressibleByExtendedGraphemeClusterLiteral
ExpressibleByStringLiteral
这三种都是由字符串初始化, 上面两种包含有 Unicode 字符和特殊字符
静态库和动态库,
静态库是每一个程序单独一份, 动态库多个程序之间共享
个人只能打包静态库
数组的对象的储蓄地址是连续的,如果越界了,那取到的地址不一定可用,所以报错。毕竟还是需要有可以信任的部分的
泛型?
func isNumber(number : T){
print(" it is a number")
}