1.Swift 到底是面向對象還是函數式的編程語言?
Swift 既是面向對象的,又是函數式的編程語言。
說 Swift 是 Object-oriented,是因為 Swift 支持類的封裝、繼承、和多態,從這點上來看與 Java 這類純面向對象的語言幾乎毫無差別。
說 Swift 是函數式編程語言,是因為 Swift 支持 map, reduce, filter, flatmap 這類去除中間狀態、數學函數式的方法,更加強調運算結果而不是中間過程。
1.map、filter、reduce 的作用
- map 是Array類的一個方法,我們可以使用它來對數組的每個元素進行轉換
let intArray = [1, 3, 5]
let stringArr = intArray.map {
return "\($0)"
}
// ["1", "3", "5"]
- filter 用于選擇數組元素中滿足某種條件的元素
let filterArr = intArray.filter {
return $0 > 1
}
//[3, 5]
- reduce 把數組元素組合計算為一個值
let result = intArray.reduce(0) {
return $0 + $1
}
//9
1.map 與 flatmap 的區別
- map 可以對一個集合類型的所有元素做一個映射操作
- 對數組進行flatmap操作,和map是沒有區別的
- 和map 不同,flatmap 有兩個定義,分別是:
func flatMap(transform: (Self.Generator.Element) throws -> T?) -> [T]
func flatMap(transform: (Self.Generator.Element) -> S) -> [S.Generator.Element]
1)
第一種情況返回值類型是 T?, 實際應用中,可以用來過濾元素為nil的情況,(內部使用了 if-let 來對nil值進行了過濾) 例如:
let optionalArray: [String?] = ["AA", nil, "BB", "CC"];
var optionalResult = optionalArray.flatMap{ $0 }
// ["AA", "BB", "CC"]
操作前是[String?], 操作后會變成[String]
2)
第二種情況會自動去重處理
let numbersCompound = [[1,2,3],[4,5,6]];
var res = numbersCompound.map { $0.map{ $0 + 2 } }
// [[3, 4, 5], [6, 7, 8]]
var flatRes = numbersCompound.flatMap { $0.map{ $0 + 2 } }
// [3, 4, 5, 6, 7, 8]
$0.map{ $0 + 2 } 會得到[3, 4, 5], [6, 7, 8], 然后遍歷這兩個數組,將遍歷的元素拼接到一個新的數組內,最終并返回就得到了[3, 4, 5, 6, 7, 8]
2.Swift 中 struct 和 class 什么區別?舉個應用中的實例
- struct沒有繼承的功能,而class是可以繼承的,這是面向對象語言的核心能力,class當然會有這個能力。
- struct 是值類型,class 是引用類型。體現在內存使用上,struct是通過值傳遞,而class是通過引用傳遞的。
看過WWDC的人都知道,struct 是蘋果推薦的,原因在于它在小數據模型傳遞和拷貝時比 class 要更安全,在多線程和網絡請求時尤其好用。我們來看一個簡單的例子:
class A {
var val = 1
}
var a = A()
var b = a
b.val = 2
此時 a 的 val 也被改成了 2,因為 a 和 b 都是引用類型,本質上它們指向同一內存。解決這個問題的方法就是使用 struct:
struct A {
var val = 1
}
var a = A()
var b = a
b.val = 2
此時 A 是struct,值類型,b 和 a 是不同的東西,改變 b 對于 a 沒有影響。
3. Swift 中定義常量和 Objective-C 中定義常量有什么區別?
OC是這樣定義常量的:
const int number = 0;
Swift 是這樣定義常量的:
let number = 0
- OC中用 const 來表示常量,而 Swift 中用 let 來判斷是不是常量。
- OC中 const 表明的常量類型和數值是在 compilation time (編譯階段)時確定的;而 Swift 中 let 只是表明常量(只能賦值一次),其類型和值既可以是靜態的,也可以是一個動態的計算方法,它們在 runtime 時確定的。
4.Swift 中的泛型
泛型是為Swift編程靈活性的一種語法,在函數、枚舉、結構體、類中都得到充分的應用,它的引入可以起到占位符的作用,當類型暫時不確定的,只有等到調用函數時才能確定具體類型的時候可以引入泛型。
我們之前實際上已經使用過泛型,例如:Swift的Array和Dictionary類型都是泛型集。
詳細介紹點我
5.給一個數組,要求寫一個函數,交換數組中的兩個元素
func swap<T>(_ nums: inout [T], _ p: Int, _ q: Int) {
(nums[p], nums[q]) = (nums[q], nums[p])
}
6.實現一個 min 函數,返回兩個元素較小的元素
func min<T: Comparable>(_ a: T, _ b: T) -> T {
return a < b ? a: b
}
//這里一定要遵守 Comparable 協議,因為并不是所有的類型都具有“可比性”
7.guard 使用場景
- 使用 guard 來表達 “提前退出”的意圖,有以下 使用場景 :
- 在驗證入口條件時
- 在成功路徑上提前退出
- 在可選值解包時(拍扁 if let..else 金字塔)
- return 和 throw 中
- 日志、崩潰和斷言中
而下面則是盡量 避免使用 的場景:
- 不要用 guard :替代瑣碎的 if..else 語句
- 不要用 guard :作為 if 的相反情況
- 不要:在 guard 的 else 語句中放入復雜代碼
具體介紹點這里
8.defer 使用場景
defer 語句用于在退出當前作用域之前執行代碼.例如:
手動管理資源時,比如 關閉文件描述符,或者即使拋出了錯誤也需要執行一些操作時,就可以使用 defer 語句。
如果多個 defer 語句出現在同一作用域內,那么它們執行的順序與出現的順序相反
func f() {
defer { print("First") }
defer { print("Second") }
defer { print("Third") }
}
f()
// 打印 “Third”
// 打印 “Second”
// 打印 “First”
9.String 與 NSString 的關系與區別
- String 是 struct,值類型。NSString 是類,引用類型。
10.Swift 訪問關鍵字
從高到低得權限控制順序如下
open > public > interal > fileprivate > private
private
swift3.0 private訪問級別所修飾的屬性或者方法只能在當前類里訪問。
class A {
private func test() {
print("this is private function!")
}
}
class B: A {
func show() {
test()
}
}
上面代碼在swift3.0以前,可以順利編譯成功,但是在swift3.0中會編譯失敗,提示class B中test()方法不可用。
fileprivate
fileprivate是Swift3.0后新加的權限修飾符,fileprivate訪問級別所修飾的屬性或者方法在當前的Swift源文件里可以訪問。(比如上面例子中把private改成fileprivate就不會報錯了)。
internal
internal為默認訪問級別,可默認不寫。internal訪問級別所修飾的屬性或方法在源代碼所在的整個模塊都可以訪問。如果是框架或者庫代碼,則在整個框架內部都可以訪問,框架由外部代碼所引用時,則不可以訪問。如果是App代碼,也是在整個App代碼,也是在整個App內部可以訪問。
public
可以被任何人訪問。但其他module中不可以被override和繼承,而在module內可以被override和繼承。
open
open為swift3.0后新加權限關鍵字,可以被任何人使用,包括override和繼承。
詳細的點這里