1.Swift與Objective-C的區(qū)別
| Swift | OC | ||
|---|---|---|---|
| 語言特性 | 靜態(tài)語言 | 動態(tài)語言 |
靜態(tài)語言由編譯器做類型推斷,一旦類型確定就無法改變 動態(tài)語言在運行時可以改變其結(jié)構(gòu) |
| 命名空間 | 有 | 無 | 同一個命名空間中的所有 Symbol不允許重名 |
| 方法調(diào)用 | 直接調(diào)用,函數(shù)表調(diào)用,消息轉(zhuǎn)發(fā) | 消息轉(zhuǎn)發(fā) |
直接派發(fā)(靜態(tài)派發(fā))編譯后就確定了方法的調(diào)用地址 函數(shù)表派發(fā)(動態(tài)派發(fā))運行時通過一個函數(shù)表查找需要執(zhí)行的方法 消息派發(fā)(動態(tài)派發(fā))運行時查找找類及父類對象的方法列表 添加final、static、@inline、@nonobjc以及值類型、Extensions的函數(shù)直接派發(fā) 添加dynamic、@objc、dynamic的函數(shù)消息派發(fā) 初始聲明函數(shù)使用函數(shù)表派發(fā) |
| 泛型/元組/高階函數(shù) | 有 | 輕量,如集合類型 |
泛型可以使我們在程序代碼中定義一些可變的部分,在運行的時候指定 元組是多個值組合成一個復合值,且值可以是任意類型 高階函數(shù)的參數(shù)或者返回值為函數(shù) |
| 語言效率 | 性能更高,速度更快 | 低 | Swift靜態(tài)編譯以及Option類型相對安全 語法簡潔、面向協(xié)議、高度抽象的泛型性能更高 值類型在??臻g單指針處理性能更快 |
| 文件特性 | .swift 單文件 | .h/.m包含頭文件 | Swift中通過Open、Public、Internal、FilePrivate、Pirvate來實現(xiàn)接口層面和實現(xiàn)成面問題 |
| 編程特性 | 函數(shù)式編程/響應(yīng)式編程/面向協(xié)議編程 | 面向?qū)ο缶幊?/td> |
函數(shù)式編程是一種思考問題的方式 響應(yīng)式編程是一種面向數(shù)據(jù)流和變化傳播的編程范式,可以簡化異步編程,提供更優(yōu)雅的數(shù)據(jù)綁定 面向協(xié)議編程協(xié)議定義提供實現(xiàn)的入口遵循協(xié)議的類型需要對其進行實現(xiàn);協(xié)議擴展為入口提供默實現(xiàn),根據(jù)入口提供額外實現(xiàn) 面向?qū)ο缶幊?/strong>使用封裝和繼承,將一系列相關(guān)的內(nèi)容放到一起 |
2.Struct與Class的區(qū)別
| Struct | Class | ||
|---|---|---|---|
| 支持繼承 | 否 | 是 | - |
| 類型 | 值類型 | 引用類型 |
值類型存放在棧區(qū),賦值為深拷貝。采用copy on write策略,優(yōu)化效率,操作僅僅是單個指針的移動,減少了堆上內(nèi)存分配和回收次數(shù) 引用類型存放在堆區(qū),賦值是淺拷貝,操作牽涉到合并,位移,重鏈接 |
| 析構(gòu)方法(deinit) | 無 | 有 | 值類型不關(guān)系引用計數(shù) |
| 初始化方法 | 默認構(gòu)造器 | 指定構(gòu)造器、便利構(gòu)造器 |
結(jié)構(gòu)體初始化的時候必須要給屬性賦值,來決定其在內(nèi)存中的布局 Class初始化的時候可以暫時不用賦值 |
| 屬性 | 聲明屬性的時候不需要賦值 | 聲明屬性的時候必須賦值或者包裝成Optional | - |
| 其他 | 方法修改屬性的時候需要用@mutating修飾 Struct 只能用Static 修飾 |
required關(guān)鍵字只支持Class 支持引用相等比較(===于!==),結(jié)構(gòu)體不支持 |
- |
3.Swift中常量與Objective-C中常量的區(qū)別
- OC中常量定義如下
const int number = 0;
ObjC中const表明的常量類型和數(shù)值是在編譯時確定的;
- Swift中常量定義如下
let number = 0
Swift 中 let 只是表明常量(只能賦值一次),其類型和值既可以是靜態(tài)的,也可以是一個動態(tài)的計算方法,它們在 runtime 運行時確定
4.!、?、??、is、as、as!、as?的定義
- !強制解包,如果值為nil,會報錯crash掉
- ?用來聲明可選值,如果變量未初始化則自動初始化nil;在操作可選值時,如果可選值時nil則不響應(yīng)后續(xù)的操作;使用as?進行向下轉(zhuǎn)型操作
- ?? 用來判斷左側(cè)可選值非空(not nil)時返回左側(cè)值可選值,左側(cè)可選值為空(nil)則返回右側(cè)的值
- is判斷某個對象是否為某個特定類的對象
- as從子類對象轉(zhuǎn)換為父類對象,向上轉(zhuǎn)型使用;消除二義性,數(shù)值類型轉(zhuǎn)換;switch語句中進行模式匹配
- as!父類對象強制轉(zhuǎn)為子類對象,如果失敗會crash,屬于向下轉(zhuǎn)型
- as?父類對象轉(zhuǎn)為子類對象,轉(zhuǎn)型不成功會返回一個nil對象,成功返回可選類型(optional),需要拆包
5.Swift中final、class、static的用法
- static修飾存儲屬性、計算屬性、類型方法,且修飾的方法不能被繼承
- class修飾計算屬性、類方法,修飾的方法可以繼承
- final修飾的類、方法、變量是不能被繼承或重寫的,且通過它可以顯示的指定函數(shù)的派發(fā)機制。
6.Swift中單例
class Tools {
static let share = Tools()
private init() {
}
}
let tools = Tools.shared
7.Swift中延遲加載(Lazy)
lazy var iOSResumeDescription: String = {
return "I am an iOS developer"
}()
懶加載存儲屬性只會在首次使用時才會計算初始值屬性,且懶加載屬性必須聲明(var)為變量,因為常量屬性(let)初始化之前會有值
8.Swift中的訪問控制權(quán)限
- open:實例可被同一模塊內(nèi)所有實體訪問,模塊外可導入該模塊即可訪問,模塊外可被繼承和重寫。
- public:實例可被同一模塊內(nèi)所有實體訪問,模塊外可導入該模塊即可訪問,模塊外不能被繼承和重寫。
- internal:實例可被同一模塊內(nèi)所有實體訪問,模塊外無法訪問。大部分實體默認是Internal級別。
- fileprivate:限制實例只能在它定義的文件內(nèi)部(源文件)訪問。
- private: 限制實體只能在它定義的作用域內(nèi)及同一文件extension中訪問。
9.Swift枚舉中關(guān)聯(lián)值與原始值的區(qū)別
- 關(guān)聯(lián)值將枚舉的成員值跟其他類型的變量關(guān)聯(lián)存儲在一起
enum Date {
case digit(year: Int, month: Int, day: Int)
case string(String)
}
- 原始值枚舉成員可以使用相同類型的默認值預先關(guān)聯(lián)
enum Grade: String {
case perfect = "A"
case great = "B"
case good = "C"
case bad = "D"
}
10.Swift存儲屬性與計算屬性的區(qū)別
- 存儲屬性即成員變量,存儲在實例對象的內(nèi)存中
-
計算屬性本質(zhì)就是方法(函數(shù)),不占用實例對象的內(nèi)存
枚舉不可以定義存儲屬性
struct Circle {
// 存儲屬性
var radius: Double
// 計算屬性
var diameter: Double {
set {
radius = newValue / 2
}
get {
return radius * 2
}
}
}
11.運算符重載
即類、結(jié)構(gòu)體、枚舉可以為現(xiàn)有的運算符提供自定義的實現(xiàn)
struct Point {
var x: Int
var y: Int
// 重載運算符
static func + (p1: Point, p2: Point) -> Point {
return Point(x: p1.x + p2.x, y: p1.y + p2.y)
}
}
var p1 = Point(x: 10, y: 10)
var p2 = Point(x: 20, y: 20)
var p3 = p1 + p2
12.關(guān)鍵字 guard 和 defer 的用法
- guard是基于一個表達式的布爾值去判斷一段代碼是否該被執(zhí)行,只有在條件不滿足的時候才會執(zhí)行這段代碼
guard let name = self.text else {
return
}
- defer的用法是,這條語句并不會馬上執(zhí)行,而是被推入棧中,直到函數(shù)結(jié)束時才再次被調(diào)用
defer {
//函數(shù)結(jié)束才調(diào)用
}
13.Swift 中的下標是什么
subscript可以給任意類型(枚舉、結(jié)構(gòu)體、類)增加下標功能,語法類似于實例方法、計算屬性,本質(zhì)就是方法(函數(shù))
class Point {
var x = 0.0, y = 0.0
subscript(index: Int) -> Double {
set {
if index == 0 {
x = newValue
} else if index == 1 {
y = newValue }
}
get {
if index == 0 {
return x
} else if index == 1 {
return y
}
return 0
}
}
}
var p = Point()
// 下標賦值
p[0] = 11.1
p[1] = 22.2
// 下標訪問
print(p.x) // 11.1
print(p.y) // 22.2
14.Swift 和OC中初始化方法 (init)的區(qū)別
swift初始化方法需要保證所有的非optional的成員變量都完成初始化, 同時新增了convenience和required
convenience必須通過一個指定初始化器來完成初始化
required是強制子類重寫父類中所修飾的初始化方法
15.什么是屬性觀察
屬性觀察是指在當前類型內(nèi)對特性屬性進行監(jiān)測,并作出響應(yīng)
- willSet會傳遞新值,默認叫newValue
- didSet會傳遞舊值,默認叫oldValue
var title: String {
willSet {
print("willSet", newValue)
}
didSet {
print("didSet", oldValue, title)
}
}
16.如何將Swift 中的協(xié)議(protocol)中的部分方法設(shè)計為可選(optional)
- 協(xié)議和方法前面添加 @objc,然后在方法前面添加 optional,實際上是將協(xié)議轉(zhuǎn)為了OC的方式
@objc protocol someProtocol {
@objc optional func test()
}
- 使用擴展(extension),來規(guī)定可選方法,在 swift 中,協(xié)議擴展可以定義部分方法的默認實現(xiàn)
protocol someProtocol {
func test()
}
extension someProtocol{
func test() {
print("test")
}
}
17.函數(shù)重載的定義,以及 swift 支不支持函數(shù)重載
函數(shù)重載是指: 函數(shù)名稱相同,函數(shù)的參數(shù)個數(shù)不同, 或者參數(shù)類型不同,或參數(shù)標簽不同, 返回值類型與函數(shù)重載無關(guān)
swift 支持函數(shù)重載
18.Swift 中閉包的結(jié)構(gòu),以及尾隨閉包、逃逸閉包和自動閉包的定義
- 閉包結(jié)構(gòu)
{
(參數(shù)列表) -> 返回值類型 in 函數(shù)體代碼
}
- 尾隨閉包,是一個書寫在函數(shù)圓括號之后的閉包表達式,函數(shù)支持將其作為最后一個參數(shù)調(diào)用
// fn 就是一個尾隨閉包參數(shù)
func exec(v1: Int, v2: Int, fn: (Int, Int) -> Int) {
print(fn(v1, v2))
}
// 調(diào)用
exec(v1: 10, v2: 20) {
$0 + $1
}
- 逃逸閉包在函數(shù)結(jié)束后調(diào)用,閉包調(diào)用逃離了函數(shù)的作用域,需要通過@escaping聲明
// 定義一個數(shù)組用于存儲閉包類型
var completionHandlers: [() -> Void] = []
// 在方法中將閉包當做實際參數(shù),存儲到外部變量中
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
someFunctionWithEscapingClosure(_:) 函數(shù)接受一個閉包作為參數(shù),該閉包被添加到一個函數(shù)外定義的數(shù)組中。如果你不將這個參數(shù)標記為 @escaping,就會得到一個編譯錯誤。
- 自動閉包不接受任何參數(shù),延遲求值,只有在被調(diào)用時才會返回被包裝在其中的表達式的值,需要通過@autoclosure聲明
func goodMooning(morning:Bool ,who:@autoclosure() -> String){
if morning {
print("Good morning, (who())")
}
}
18.可選鏈的定義
可選鏈是一個調(diào)用和查詢可選屬性、方法和下標的過程,它可能為 nil
如果可選項包含值,屬性、方法或者下標的調(diào)用成功
如果可選項是 nil ,屬性、方法或者下標的調(diào)用會返回 nil 。
多個查詢可以鏈接在一起,如果鏈中任何一個節(jié)點是 nil ,那么整個鏈就會得體地失敗
19.OC和Swift中的擴展(Extension)區(qū)別
- OC中有分類和擴展
- Swift中只有擴展(更類似OC中的分類)
- Swif Extension中不可以直接添加屬性,編譯會報錯
- 類、結(jié)構(gòu)體、枚舉類型或者協(xié)議類型都可以添加擴展
20.交換數(shù)組中的兩個元素
func swap<T>(nums: inout [T], p: Int , q : Int) {
(nums[p], nums[q]) = (nums[q], nums[p]);
}
func swap(a: inout Int, b: inout Int) {
(a, b) = (b , a)
}
func swap<T, U>(x: T, y: U) -> (T, U) {
return (y, x)
}
21.實現(xiàn)一個 min 函數(shù),返回兩個元素中較小的元素
func min<T : Comparable>(_ a : T , b : T) -> T {
return a < b ? a : b
}
22.map、filter、reduce、flatmap 的作用
- map映射,將一個元素根據(jù)某個函數(shù) 映射 成另一個元素(可以是同類型,也可以是不同類型)
- flatmap可以將元素映射成可選類型
- filter 過濾,將一個元素傳入閉包中,如果返回的是false , 就過濾掉
- reduce先映射后融合,將數(shù)組中的所有元素映射融合在一起
23.利用Swift 的 Currying(柯里化) 特性,輸入任一整數(shù),輸出輸入的整數(shù)+2
柯里化(Currying) 將原來接受兩個參數(shù)的函數(shù)變成新的接受一個參數(shù)的函數(shù)的過程。新的函數(shù)返回一個以原有第二個參數(shù)為參數(shù)的函數(shù)
func addOne(count: Int) -> Int {
return count + 2
}
func add(count: Int, addition: Int) -> Int {
return count + addition
}
func add(_ addition: Int) -> (Int) -> Int {
return {
count in
return count + addition
}
}
24.為什么數(shù)組索引越界會Crash,而字典用下標取值時 key 沒有對應(yīng)值的話返回的是 nil 不會Crash
- 數(shù)組是一段連續(xù)內(nèi)存地址,越界訪問也能訪問到內(nèi)存,但這段內(nèi)存不一定可用,所以會引起Crash
- 字典的key并沒有對應(yīng)確定的內(nèi)存地址,所以是安全的
25.associatedtype(關(guān)聯(lián)類型) 的作用
- 給協(xié)議中用到的類型定義一個占位名稱
- 協(xié)議中可以擁有多個關(guān)聯(lián)類型
26.聲明一個只有一個參數(shù)沒有返回值閉包的別名
typealias SomeClosuerType = (String) -> (Void)
let someClosuer: SomeClosuerType = { (name: String) in
print("hello,", name)
}
someClosuer("world")