翻了 喵神 和 SwiftGG 的資料, 借鑒了 Arco_vv 和 Enum 的回答, ...算是查漏補(bǔ)缺
1. class 和 struct 的區(qū)別
- 結(jié)構(gòu)體(和枚舉, 元組)是值類(lèi)型, 類(lèi)(和函數(shù), 閉包)是引用類(lèi)型.
- 類(lèi)可以通過(guò)繼承來(lái)共享代碼. 而結(jié)構(gòu)體(和枚舉)不能被繼承.
結(jié)構(gòu)體共享代碼可以用組合, 泛型以及協(xié)議擴(kuò)展
2. 不通過(guò)繼承, 代碼復(fù)用(共享)的方式有哪些
- 協(xié)議擴(kuò)展
- 泛型
- 組合
3. Set 獨(dú)有的方法有哪些
-
Set與Array,Dictionary是 Swift 提供的三種基本集合類(lèi)型,
數(shù)據(jù)類(lèi)型必須明確, 且遵循Hashable, 被實(shí)現(xiàn)為泛型集合
Array是有序數(shù)據(jù)集;
Set是無(wú)序無(wú)重復(fù)數(shù)據(jù)的集;
Dictionary是無(wú)序的鍵值對(duì)的集當(dāng)集合元素順序不重要或者希望每個(gè)元素只出現(xiàn)一次時(shí)可以使用 Set
-
操作方法
-
a.intersection(b)a 與 b 的交集 -
a.symmetricDifference(b)a 與 b 的對(duì)等差分(a 與 b 獨(dú)有元素的并集) -
a.union(b)a 與 b 的并集 -
a.subtracting(b)a 與 b 的差集(屬于 a 不屬于 b)
-
-
判斷方法
-
a.isSubset(of: b)a 是否是 b 的子集 -
a.isSuperset(of: b)a 是否包含 b -
a.isStrictSubset(of: b)a 是否是 b 的子集 并且 a 與 b 不相等 -
a.isStrictSuperset(of: b)a 是否包含 b 并且 a 與 b 不相等 -
a.isDisjoint(with: b)a 是否與 b 沒(méi)有交集
-
4. 實(shí)現(xiàn)一個(gè) min 函數(shù), 返回兩個(gè)元素較小的元素
func min<T: Comparable>(a: T, b: T) -> T {
return a < b ? a : b
}
5. map, filter, reduce 的作用
-
map函數(shù)能夠被集合調(diào)用,它接受一個(gè)閉包作為參數(shù),作用于數(shù)組中的每個(gè)元素。閉包返回一個(gè)變換后的元素,接著將所有這些變換后的元素組成一個(gè)新的集合(集合類(lèi)型與值可以改變, 但是數(shù)量不變)并返回; -
filter(過(guò)濾器) 傳入一個(gè)返回Bool類(lèi)型的函數(shù) 保留返回值為true的元素 -
reduce中的參數(shù)為兩個(gè):一個(gè)初始值、一個(gè)combine閉包.reduce把集合中所有的值合并成 一個(gè)新值, 該值類(lèi)型可以與原元素值不同
6. map 與 flatmap 的區(qū)別
-
map返回的集合元素?cái)?shù)量與原集合一致 -
flatMap返回后的集合中不存在nil, 可以把Optional解包 -
flatMap可以把集合降維
7. 什么是 copy on write
- Swift 中的寫(xiě)時(shí)復(fù)制是指,值類(lèi)型只在 引用不唯一 并且 被改動(dòng) 前進(jìn)行復(fù)制
傳統(tǒng)意義上的值類(lèi)型會(huì)在被傳遞或者被賦值給其他變量時(shí)就發(fā)生復(fù)制行為,但是這將會(huì)帶來(lái)極大的,也是不必要的性能損耗。
寫(xiě)時(shí)復(fù)制將在值被傳遞和賦值給變量時(shí)首先檢查其引用計(jì)數(shù),如果引用計(jì)數(shù)為 1 (唯一引用),那么意味著并沒(méi)有其他變量持有該值,對(duì)當(dāng)前值的復(fù)制也就可以完全避免,以此在保持值類(lèi)型不可變性的優(yōu)良特性的同時(shí),保證使用效率。
8. 如何獲取當(dāng)前代碼的函數(shù)名和行號(hào)
func getInfo(name: String = #function, line: Int = #line) {}
getInfo()
9. 如何聲明一個(gè)只能被類(lèi) conform 的 protocol
protocol MyProtocol: class {}
10. guard 使用場(chǎng)景
- 解包, 避免
if let else嵌套
11. defer 使用場(chǎng)景
用 defer 聲明一個(gè) block,當(dāng)前代碼執(zhí)行的閉包退出時(shí)會(huì)執(zhí)行該 block。
使用場(chǎng)景: 函數(shù)返回是一定要執(zhí)行一些代碼, 就放在defer代碼塊里面
12. String 與 NSString 的關(guān)系與區(qū)別
String 是 struct, 是值類(lèi)型, 性能比 NSString 占優(yōu)
NSString 繼承自 NSObject, 是引用類(lèi)型 擁有動(dòng)態(tài)特性
String 可以使用 characters 進(jìn)行枚舉
13. 怎樣獲取一個(gè) String 的長(zhǎng)度
let length1 = "string".characters.count
let length2 = "string".data(using: .utf8)
let length3 = ("string" as NSString).length
14. 如何截取 String 的某段字符串
extension String {
/// 截取字符串(包括邊界)
///
/// - Parameter range: 截取的邊界
/// - Returns: 截取后的字符串
func subString(_ lower: Int, _ upper: Int) -> String {
let startOffSet = lower < 0 ? 0 : lower
let endOffSet = upper > self.characters.count ? self.characters.count : upper
let start = self.index(self.startIndex, offsetBy: startOffSet)
let end = self.index(self.startIndex, offsetBy: endOffSet)
let subRange = Range.init(uncheckedBounds: (lower: start, upper: end))
return self.substring(with: subRange)
}
}
15. throws 和 rethrows 的用法與作用
-
rethrow和throws表示該函數(shù)里可能會(huì)拋出異常, 調(diào)用該函數(shù)時(shí)需要處理此異常 -
rethrows一般用在參數(shù)中含有可以throws的方法的高階函數(shù)中 - 要
throws另一個(gè)throws時(shí),應(yīng)該將前者改為rethrows, 提高可讀性與準(zhǔn)確性
//符合拋出異常條件時(shí)
func doSomething() throws {
if somthingIsError {
throw CustomError
}
//或者配合 do catch / try / try?
}
func methodRethrows(num: Int, f: (Int) throws -> ()) rethrows {
try f(num)
}
16. try? 和 try! 是什么意思
在可能發(fā)生異常的語(yǔ)句前加 try
-
try!表示強(qiáng)制執(zhí)行, 確定其不會(huì)拋出異常, 如果調(diào)用中出現(xiàn)異常, 程序?qū)⒈罎? 這與對(duì)Optional值用 ! 進(jìn)行強(qiáng)制解包的行為是一致的. -
try?會(huì)返回一個(gè)Optional值, 如果運(yùn)行成功, 會(huì)包含這條語(yǔ)句的返回值, 否則將返回nil, 并且意味著無(wú)視了錯(cuò)誤的具體類(lèi)型
17. associatedtype 的作用
-
被用作協(xié)議中的泛型約束
在協(xié)議中使用
associatedtype可以讓實(shí)現(xiàn)此協(xié)議的對(duì)象限定協(xié)議方法中參數(shù)的類(lèi)型
18. 什么時(shí)候使用 final
-
final關(guān)鍵字可以用在class,func或者var前面進(jìn)行修飾, 表示不允許對(duì)該內(nèi)容進(jìn)行繼承或者重寫(xiě)操作.
19. pubic 和 open 的區(qū)別
- 只有被
open標(biāo)記的內(nèi)容才能在別的框架中被繼承或者重寫(xiě)
20. 聲明只有一個(gè)參數(shù)沒(méi)有返回值閉包的別名
typealias myBlock = (String) -> Void
21. Self 的使用場(chǎng)景
- 在協(xié)議中使用表示當(dāng)前類(lèi)型, 類(lèi)似
associatedtype的作用, 所以使用Self的協(xié)議只能被用作泛型約束, 不能用作獨(dú)立類(lèi)型, 因?yàn)橹挥蝎@知實(shí)際類(lèi)型Self才有意義
protocol Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool
}
- 擴(kuò)展協(xié)議時(shí)用來(lái)做類(lèi)型約束
protocol MyProtocol { }
extension MyProtocol where Self: UIView { }
22. dynamic 的作用
Swift 中使用 KVO 僅限于 NSObject 的子類(lèi)
該類(lèi)屬性添加 dynamic 關(guān)鍵字
可以把該屬性添加到動(dòng)態(tài)查找列表中 使其可以被動(dòng)態(tài)調(diào)用, 即可實(shí)現(xiàn)KVO
23. 什么時(shí)候使用 @objc
使用@objc 修飾后的類(lèi)型, 可以直接被 Objective-C 調(diào)用
-
可以被
@objc修飾的類(lèi)型:- 未嵌套的類(lèi)
- 協(xié)議
- 非泛型枚舉 (僅限于原始值為整形的枚舉)
- 類(lèi)和協(xié)議中的屬性和方法
- 構(gòu)造器和析構(gòu)器
- 下標(biāo)
Swift 中聲明繼承
NSObject的類(lèi), 會(huì)被自動(dòng)加上@objc修飾-
Swift 中使用中文類(lèi)名時(shí), 若想讓 Objective-C 調(diào)用
@objc(MyClass)
class 我的類(lèi): NSObject {
@objc(greeting:)
func 打招呼(名字: String) {
print("哈嘍,(名字)")
}
}
- 若想在協(xié)議中實(shí)現(xiàn) `optional` 方法 除了擴(kuò)展協(xié)議, 還可以直接 添加 `@objc` 修飾符, 在方法前添加 `optional` 關(guān)鍵字
@objc protocol CounterDataSource {
optional func incrementForCount(count: Int) -> Int
optional var fixedIncrement: Int { get }
}
###24. Optional (可選型) 是怎么實(shí)現(xiàn)的
- `Optional` 是一個(gè)泛型枚舉, 有兩個(gè)枚舉成員, 一個(gè)是 `.some(Wrapped)`, 一個(gè)是 `.none`,
- 實(shí)現(xiàn) `ExpressibleByNilLiteral` 協(xié)議, 可以接收 `nil`
###25. 如何自定義下標(biāo)獲取
class MyClass {
private let a = ["a", "b"]
subscript(index: Int) -> String {
return a[index]
}
}
###26. ?? 的作用
- 語(yǔ)法糖. 嘗試取得 `Optional` 值時(shí), 聲明當(dāng) `Optional` 為 `.none` 時(shí), 使用 `??` 右邊的值.
- 另外右邊的值為閉包時(shí), 被 `@autoclosure` 優(yōu)化, 獲取值若不為 `nil`, 則不會(huì)被執(zhí)行
###27. lazy 的作用
- 延遲計(jì)算, 實(shí)現(xiàn)惰性初始化, 如果不訪問(wèn)該屬性, 它的缺省值就不會(huì)被計(jì)算, 可以用閉包做初始化時(shí)可以調(diào)用 `self`, 因?yàn)楫?dāng)它需要計(jì)算出來(lái)的時(shí)候, `self` 已經(jīng)初始化完成, 并且該閉包屬于瞬發(fā)閉包, 不會(huì)產(chǎn)生循環(huán)引用
- 由于它在沒(méi)有值的情況下被初始化, 然后被訪問(wèn)時(shí)改變自己的值, 所以該屬性不能是 `lazy let`
- 聲明在全局作用域下 和 類(lèi)型屬性(聲明為 `static let` , 而非實(shí)例屬性) 的常量是自動(dòng)具有惰性( `lazy` ) 的, 并且線程安全
- `SequenceType` 和 `CollectionType` 協(xié)議都有一個(gè) `lazy` 計(jì)算屬性, 它能返回一個(gè)特殊的 `LazySequence` 或者 `LazyCollection`; 這種方法只能被用在 `map`, `flatMap`, `filter` 這樣的高階函數(shù)中, 是一種惰性的方式. 實(shí)現(xiàn)當(dāng)值被訪問(wèn)時(shí)才會(huì)調(diào)用傳入的函數(shù), 對(duì)于龐大的序列, 可以提高很多效率
func double(x: Int) -> Int {
print("Computing double value of (x)…")
return 2*x
}
let doubleArray = array.lazy.map(increment).map(double)
print(doubleArray[3])
只用當(dāng) `array[3]` 被訪問(wèn)時(shí), `double(increment(array[3]))` 才會(huì)執(zhí)行
###28. 一個(gè)類(lèi)型表示選項(xiàng), 可以同時(shí)表示有幾個(gè)選項(xiàng)選中(類(lèi)似 UIViewAnimationOptions), 用什么類(lèi)型表示
- 實(shí)現(xiàn) `OptionSet` 協(xié)議的結(jié)構(gòu)體 只需要一個(gè)整型的原始值(`rawValue`)
###29. inout 的作用
- Swift 常規(guī)方法中經(jīng)常用到的是值傳遞。
值傳遞最明顯的后果便是無(wú)法對(duì)原數(shù)據(jù)進(jìn)行直接修改。
如果我們需要處理后的數(shù)據(jù)結(jié)果,那么就需要重新定義一個(gè)變量來(lái)接收值。
在原數(shù)據(jù)被廢棄的情況下,這樣既增多了代碼量,也產(chǎn)生了空間大量浪費(fèi)。
因此 Swift 提供了關(guān)鍵字修飾 `inout` 來(lái)申明數(shù)據(jù)地址傳遞,也稱(chēng)之為引用傳遞。
###30. Error 如果兼容 NSError 需要做什么操作
- 定義 `CustomNSError` 協(xié)議, 繼承自 `Error` 用來(lái)橋接原來(lái) `NSError` 中的 `code`、`domain`、`UserInfo`.
public protocol CustomNSError : Error {
/// The domain of the error.
public static var errorDomain: String { get }
/// The error code within the given domain.
public var errorCode: Int { get }
/// The user-info dictionary.
public var errorUserInfo: [String : Any] { get }
}
如果想讓我們的自定義 `Error` 可以轉(zhuǎn)成 `NSError`,實(shí)現(xiàn) `CustomNSError` 就可以完整的 `as NSError`.
###31. 下面的代碼都用了哪些語(yǔ)法糖 / [1, 2, 3].map{ $0 * 2 }
`[1, 2, 3].map{ $0 * 2 }`
- 數(shù)組的語(yǔ)法糖 `[1, 2, 3]` 表示 `Array<Int>` 類(lèi)型的數(shù)組
- 唯一參數(shù)尾隨閉包, 可以省略括號(hào)
- `$0` 表示第一個(gè)參數(shù), 省略了參數(shù)名的聲明
- 單行表達(dá)式閉包可以省略 `return`
###32. 什么是高階函數(shù)
- 以函數(shù)為參數(shù)的函數(shù)就是高階函數(shù)
- 接收函數(shù)為參數(shù), 并返回另一個(gè)函數(shù)的高階函數(shù)為柯里化(Curry)函數(shù)
###33. 如何解決引用循環(huán)
- 使其中一個(gè)引用對(duì)象屬性聲明為 `weak` 或 `unowned`
###34. 下面的代碼會(huì)不會(huì)崩潰,說(shuō)出原因
var mutableArray = [1,2,3]
for _ in mutableArray {
mutableArray.removeLast()
}
- 不會(huì)崩潰, 引用唯一, 不會(huì)復(fù)制, 執(zhí)行三次 `.removeLast()` 每次都會(huì)重新尋找下標(biāo)
###35. 給集合中元素是字符串的類(lèi)型增加一個(gè)擴(kuò)展方法,應(yīng)該怎么聲明
extension Collection where Iterator.Element == String {
func whatever() { }
}
["", ""].whatever()
###36. 定義靜態(tài)方法時(shí)關(guān)鍵字 static 和 class 有什么區(qū)別
- 被 `class` 修飾的方法可以被子類(lèi)重寫(xiě)
- `static` 可以修飾結(jié)構(gòu)體, 枚舉和類(lèi)的靜態(tài)方法, `class` 只能修飾類(lèi)的靜態(tài)方法
---
##高級(jí)
###1. 一個(gè) Sequence 的索引是不是一定從 0 開(kāi)始?
- 不一定 可以自定義 `Generator` 改變其初始值, 還可以自定義排序方法
- 比如 `ArraySlice`
###2. 數(shù)組都實(shí)現(xiàn)了哪些協(xié)議
- `RandomAccessCollection`
- `MutableCollection` : `MutableIndexable`, `Collection`
- ...還是看文檔吧
###3. 如何自定義模式匹配
- 實(shí)現(xiàn) `~=` 運(yùn)算符, 第一個(gè)參數(shù)是 `case` 對(duì)象, 第二個(gè)參數(shù)是 `switch` 的對(duì)象
###4. autoclosure 的作用
- 把一句表達(dá)式自動(dòng)封裝成一個(gè)閉包
func f(_ foo: @autoclosure ()->Bool) { }
f(true)
###5. 編譯選項(xiàng) whole module optmization 優(yōu)化了什么
- 減少編譯時(shí)間, 編譯時(shí)對(duì)同屬一個(gè) Module 的源碼做整體分析, 而不是單文件分析
- 排除從不調(diào)用的函數(shù)
###6. 下面代碼中 mutating 的作用是什么
struct Person {
var name: String {
mutating get {
return store
}
}
}
這個(gè)...寫(xiě)不寫(xiě) `mutating` 的區(qū)別 不知道
###7. 如何讓自定義對(duì)象支持字面量初始化
- ExpressibleByNilLiteral
- ExpressibleByIntegerLiteral
- ExpressibleByFloatLiteral
- ExpressibleByBooleanLiteral
- ExpressibleByStringLiteral
- ExpressibleByArrayLiteral
- ExpressibleByDictionaryLiteral
- 實(shí)現(xiàn)對(duì)應(yīng)協(xié)議, 即可支持對(duì)應(yīng)字面量初始化
###8. dynamic framework 和 static framework 的區(qū)別是什么
- 動(dòng)態(tài)庫(kù)文件名后綴:.dylib和.framework; 靜態(tài)庫(kù)文件名后綴:.a和.framework
- 靜態(tài)庫(kù):鏈接時(shí),靜態(tài)庫(kù)會(huì)被完整地復(fù)制到可執(zhí)行文件中,被多次使用就有多份冗余拷貝
- 系統(tǒng)動(dòng)態(tài)庫(kù):鏈接時(shí)不復(fù)制,程序運(yùn)行時(shí)由系統(tǒng)動(dòng)態(tài)加載到內(nèi)存,供程序調(diào)用,系統(tǒng)只加載一次,多個(gè)程序共用,節(jié)省內(nèi)存
---
##哲學(xué)
###1. 為什么數(shù)組索引越界會(huì)崩潰,而字典用下標(biāo)取值時(shí) key 沒(méi)有對(duì)應(yīng)值的話返回的是 nil 不會(huì)崩潰。
"一款語(yǔ)言必須要有一些基礎(chǔ)的可以完全信任的東西,否則就會(huì)陷入循環(huán)驗(yàn)證的悖論。所以第一題的答案就是,數(shù)組取下標(biāo)被設(shè)計(jì)為可以完全信任的操作。" -- [Enum](http://www.itdecent.cn/u/bbb690a0f0fb)
###2. 一個(gè)函數(shù)的參數(shù)類(lèi)型只要是數(shù)字(Int、Float)都可以,要怎么表示
func myMethod<T>(_ value: T) where T: ExpressibleByIntegerLiteral, T: ExpressibleByFloatLiteral {
}
-- [Arco_vv](http://www.itdecent.cn/u/07d93406ec39)