iOS | 面試知識整理 - Swift 基礎(九)

前言:

最近公司項目不怎麼忙, 閒暇時間把iOS 在面試中可能會遇到的問題整理了一番, 一部分題目是本身面試遇到的,一部分題目則是網上收錄的, 方便本身鞏固複習, 也分享給你們! 知識點比較多,比較雜,這裏作了分類,下面是分類連接地址;git

面試知識點整理 - 目錄:面試

iOS | 面試知識整理 - OC基礎 (一)
iOS | 面試知識整理 - OC基礎 (二)
iOS | 面試知識整理 - OC基礎 (三)
iOS | 面試知識整理 - UI 相 關 (四)
iOS | 面試知識整理 - 內存管理 (五)
iOS | 面試知識整理 - 多 線 程 (六)
iOS | 面試知識整理 - 網絡相關 (七)
iOS | 面試知識整理 - 數據持久化 (八)
iOS | 面試知識整理 - Swift 基礎 (九)編程

iOS | 面試知識整理 - Swift 基礎(九)

1. 介紹一下 Swift?

Swift是蘋果在2014年6月WWDC發佈的全新編程語言,借鑑了JS,Python,C#,Ruby等語言特性,看上去偏腳本化,Swift 仍支持 cocoa touch 框架swift

他的優勢:api

  1. Swift更加安全,它是類型安全的語言。
  2. Swift容易閱讀,語法和文件結構簡易化。
  3. Swift更易於維護,文件分離後結構更清晰。
  4. Swift代碼更少,簡潔的語法,能夠省去大量冗餘代碼
  5. Swift速度更快,運算性能更高。

2. Swift 和OC 如何相互調用?

  • Swift 調用 OC代碼
    須要建立一個 Target-BriBridging-Header.h 的橋文件,在喬文件導入須要調用的OC代碼頭文件便可數組

  • OC 調用 Swift代碼
    直接導入 Target-Swift.h文件便可, Swift若是須要被OC調用,須要使用@objc 對方法或者屬性進行修飾安全

3. 類(class) 和 結構體(struct) 有什麼區別?

在 Swift 中,class 是引用類型(指針類型), struct 是值類型bash

值類型微信

  • 值類型在傳遞和賦值時將進行復制; 賦值給var、let或者給函數傳參,是直接將全部內容拷貝一份, 相似於對文件進行copy、paste操做,產生了全新的文件副本。屬於深拷貝(deep copy)
  • 值類型: 好比結構體,枚舉,是在棧空間上存儲和操做的

引用類型網絡

  • 引用類型只會使用引用對象的一個"指向"; 賦值給var、let或者給函數傳參,是將內存地址拷貝一份,相似於製做一個文件的替身(快捷方式、連接),指向的是同一個文件。屬於淺拷貝(shallow copy)
  • 引用類型: 好比 Class,是在堆空間上存儲和操做的

4. class 和 struct 比較,優缺點?

class 有如下功能,struct 是沒有的:

  1. class能夠繼承,子類可使用父類的特性和方法
  2. 類型轉換能夠在運行時檢查和解釋一個實例對象
  3. class能夠用 deinit來釋放資源
  4. 一個類能夠被屢次引用

struct 優點:

  1. 結構較小,適用於複製操做,相比較一個class 實例被屢次引用,struct 更安全
  2. 無需擔憂內存泄露問題

5. Swift 中,什麼可選型(Optional)

  • 在 Swift 中,可選型是爲了表達一個變量爲空的狀況,當一個變量爲空,他的值就是 nil
  • 在類型名稱後面加個問號? 來定義一個可選型
  • 值類型或者引用類型均可以是可選型變量
var name: String? // 默認爲 nil
var age: Int?     // 默認爲nil
print(name, age) // 打印 nil, nil
複製代碼

6.Swift,什麼是泛型?

  • 泛型主要是爲增長代碼的靈活性而生的,它能夠是對應的代碼知足任意類型的的變量或方法;
  • 泛型能夠將類型參數化,提升代碼複用率,減小代碼量
// 實現一個方法,能夠交換實現任意類型
func swap<T>(a: inout T, b: inout T) {
    (a, b) = (b, a)
}
複製代碼

7. 訪問控制關鍵字 open, public, internal, fileprivate, private 的區別?

Swift 中有個5個級別的訪問控制權限,從高到低依次是 open, public, internal, fileprivate, private

它們遵循的基本規則: 高級別的變量不容許被定義爲低級別變量的成員變量,好比一個 private 的 class 內部容許包含 public的 String值,反之低級變量能夠定義在高級別變量中;

  • open: 具有最高訪問權限,其修飾的類能夠和方法,能夠在任意 模塊中被訪問和重寫.
  • public: 權限僅次於 open,和 open 惟一的區別是: 不容許其餘模塊進行繼承、重寫
  • internal: 默認權限, 只容許在當前的模塊中訪問,能夠繼承和重寫,不容許在其餘模塊中訪問
  • fileprivate: 修飾的對象只容許在當前的文件中訪問;
  • private: 最低級別訪問權限,只容許在定義的做用域內訪問

8.關鍵字:Strong,Weak,Unowned 區別?

  • Swift 的內存管理機制同OC一致,都是ARC管理機制; Strong,和 Weak用法同OC同樣

  • Unowned(無主引用), 不會產生強引用,實例銷燬後仍然存儲着實例的內存地址(相似於OC中的unsafe_unretained), 試圖在實例銷燬後訪問無主引用,會產生運行時錯誤(野指針)

9. 如何理解copy-on-write?

值類型(好比:struct),在複製時,複製對象與原對象實際上在內存中指向同一個對象,當且僅當修改複製的對象時,纔會在內存中建立一個新的對象,

  • 爲了提高性能,Struct, String、Array、Dictionary、Set採起了Copy On Write的技術
  • 好比僅當有「寫」操做時,纔會真正執行拷貝操做
  • 對於標準庫值類型的賦值操做,Swift 能確保最佳性能,全部不必爲了保證最佳性能來避免賦值

10.什麼是屬性觀察?

屬性觀察是指在當前類型內對特性屬性進行監測,並做出響應,屬性觀察是 swift 中的特性,具備2種, willsetdidset

var title: String {
    willSet {
        print("willSet", newValue)

    }
    didSet {
        print("didSet", oldValue, title)
    }
}
複製代碼
  • willSet會傳遞新值,默認叫newValue
  • didSet會傳遞舊值,默認叫oldValue
  • 在初始化器中設置屬性值不會觸發willSet和didSet

11. swift 爲何將 String,Array,Dictionary設計爲值類型?

  • 值類型和引用類型相比,最大優點能夠高效的使用內存,值類型在棧上操做,引用類型在堆上操做,棧上操做僅僅是單個指針的移動,而堆上操做牽涉到合併,位移,重連接,Swift 這樣設計減小了堆上內存分配和回收次數,使用 copy-on-write將值傳遞與複製開銷降到最低

12.如何將Swift 中的協議(protocol)中的部分方法設計爲可選(optional)?

  • 在協議和方法前面添加 @objc,而後在方法前面添加 optional關鍵字,改方式其實是將協議轉爲了OC的方式
@objc protocol someProtocol {
  @objc  optional func test()
}
複製代碼
  • 使用擴展(extension),來規定可選方法,在 swift 中,協議擴展能夠定義部分方法的默認實現
protocol someProtocol {
    func test()
}

extension someProtocol{
    func test() {
        print("test")
    }
}
複製代碼

13.比較Swift 和OC中的初始化方法 (init) 有什麼不一樣?

swift 的初始化方法,更加嚴格和準確, swift初始化方法須要保證全部的非optional的成員變量都完成初始化, 同時 swfit 新增了convenience和 required兩個修飾初始化器的關鍵字

  • convenience只提供一種方便的初始化器,必須經過一個指定初始化器來完成初始化
  • required是強制子類重寫父類中所修飾的初始化方法

14.比較 Swift和OC中的 protocol 有什麼不一樣?

  • Swift 和OC中的 protocol相同點在於: 二者均可以被用做代理;
  • 不一樣點: Swift中的 protocol還能夠對接口進行抽象,能夠實現面向協議,從而大大提升編程效率,Swift中的protocol能夠用於值類型,結構體,枚舉;

15.swift 和OC 中的自省 有什麼區別?

自省在OC中就是判斷某一對象是否屬於某一個類的操做,有如下2中方式

[obj iskinOfClass:[SomeClass class]]
[obj isMemberOfClass:[SomeClass class]]
複製代碼

在 Swift 中因爲不少 class 並不是繼承自 NSObject, 故而 Swift 使用 is 來判斷是否屬於某一類型, is 不只能夠做用於class, 仍是做用於enumstruct

16.什麼是函數重載? swift 支不支持函數重載?

  • 函數重載是指: 函數名稱相同,函數的參數個數不一樣, 或者參數類型不一樣,或參數標籤不一樣, 返回值類型與函數重載無關
  • swift 支持函數重載

17.swift 中的枚舉,關聯值 和 原始值的區分?

  • 關聯值--有時會將枚舉的成員值跟其餘類型的變量關聯存儲在一塊兒,會很是有用

    // 關聯值
    enum Date {
    case digit(year: Int, month: Int, day: Int)
    case string(String)
    }
    複製代碼
  • 原始值--枚舉成員可使用相同類型的默認值預先關聯,這個默認值叫作:原始值

    // 原始值
    enum Grade: String {
      case perfect = "A"
      case great = "B"
      case good = "C"
      case bad = "D"
    }
    複製代碼

18. swift 中的閉包結構是什麼樣子的?

{
    (參數列表) -> 返回值類型 in 函數體代碼
}
複製代碼

19. 什麼是尾隨閉包?

  • 將一個很長的閉包表達式做爲函數的最後一個實參
  • 使用尾隨閉包能夠加強函數的可讀性
  • 尾隨閉包是一個被書寫在函數調用括號外面(後面)的閉包表達式
// fn 就是一個尾隨閉包參數
func exec(v1: Int, v2: Int, fn: (Int, Int) -> Int) {
    print(fn(v1, v2))
}

// 調用
exec(v1: 10, v2: 20) {
    $0 + $1
}
複製代碼

20. 什麼是逃逸閉包?

當閉包做爲一個實際參數傳遞給一個函數或者變量的時候,咱們就說這個閉包逃逸了,能夠在形式參數前寫 @escaping 來明確閉包是容許逃逸的。

  • 非逃逸閉包、逃逸閉包,通常都是當作參數傳遞給函數
  • 非逃逸閉包:閉包調用發生在函數結束前,閉包調用在函數做用域內
  • 逃逸閉包:閉包有可能在函數結束後調用,閉包調用逃離了函數的做用域,須要經過@escaping聲明
// 定義一個數組用於存儲閉包類型
var completionHandlers: [() -> Void] = []

//  在方法中將閉包當作實際參數,存儲到外部變量中
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}
複製代碼

若是你不標記函數的形式參數爲 @escaping ,你就會遇到編譯時錯誤。

21. 什麼是自動閉包?

自動閉包是一種自動建立的用來把做爲實際參數傳遞給函數的表達式打包的閉包。它不接受任何實際參數,而且當它被調用時,它會返回內部打包的表達式的值。這個語法的好處在於經過寫普通表達式代替顯式閉包而使你省略包圍函數形式參數的括號。

func getFirstPositive(_ v1: Int, _ v2: @autoclosure () -> Int) -> Int? {
    return v1 > 0 ? v1 : v2()
}
getFirstPositive(10, 20)
複製代碼
  • 爲了不與指望衝突,使用了@autoclosure的地方最好明確註釋清楚:這個值會被推遲執行
  • @autoclosure 會自動將 20 封裝成閉包 { 20 }
  • @autoclosure 只支持 () -> T 格式的參數
  • @autoclosure 並不是只支持最後1個參數
  • 有@autoclosure、無@autoclosure,構成了函數重載

若是你想要自動閉包容許逃逸,就同時使用 @autoclosure 和 @escaping 標誌。

22. swift中, 存儲屬性和計算屬性的區別?

Swift中跟實例對象相關的屬性能夠分爲2大類

存儲屬性(Stored Property)

  • 相似於成員變量這個概念
  • 存儲在實例對象的內存中
  • 結構體、類能夠定義存儲屬性
  • 枚舉不能夠定義存儲屬性

計算屬性(Computed Property)

  • 本質就是方法(函數)
  • 不佔用實例對象的內存
  • 枚舉、結構體、類均可以定義計算屬性
struct Circle {
    // 存儲屬性
    var radius: Double
    // 計算屬性
    var diameter: Double {
        set {
            radius = newValue / 2
        }
        get {
            return radius * 2
        }
    }
}
複製代碼

23. 什麼是延遲存儲屬性(Lazy Stored Property)?

使用lazy能夠定義一個延遲存儲屬性,在第一次用到屬性的時候纔會進行初始化(相似OC中的懶加載)

  • lazy屬性必須是var,不能是let
    • let必須在實例對象的初始化方法完成以前就擁有值
  • 若是多條線程同時第一次訪問lazy屬性
    • 沒法保證屬性只被初始化1次
class PhotoView {
    // 延遲存儲屬性
    lazy var image: Image = {
        let url = "https://...x.png"        
        let data = Data(url: url)
        return Image(data: data)
    }() 
} 
複製代碼

24. 什麼是屬性觀察器?

能夠爲非lazy的var存儲屬性設置屬性觀察器,經過關鍵字willSetdidSet來監聽屬性變化

struct Circle {
    var radius: Double {
        willSet {
            print("willSet", newValue)
        } 
        didSet {
            print("didSet", oldValue, radius)
        }
    } 
    init() {
        self.radius = 1.0
        print("Circle init!")
    }
}
複製代碼

25. swift中什麼類型屬性(Type Property)?

嚴格來講,屬性能夠分爲

實例屬性(Instance Property): 只能經過實例對象去訪問

  • 存儲實例屬性(Stored Instance Property):存儲在實例對象的內存中,每一個實例對象都有1份
  • 計算實例屬性(Computed Instance Property)

類型屬性(Type Property):只能經過類型去訪問

  • 存儲類型屬性(Stored Type Property):整個程序運行過程當中,就只有1分內存(相似於全局變量)
  • 計算類型屬性(Computed Type Property)

能夠經過static定義類型屬性 p若是是類,也能夠用關鍵字class

struct Car {
    static var count: Int = 0
    init() {
        Car.count += 1
    }
}
複製代碼

不一樣於存儲實例屬性,你必須給存儲類型屬性設定初始值

  • 由於類型沒有像實例對象那樣的init初始化器來初始化存儲屬性

存儲類型屬性默認就是lazy,會在第一次使用的時候才初始化

  • 就算被多個線程同時訪問,保證只會初始化一次
  • 存儲類型屬性能夠是let

枚舉類型也能夠定義類型屬性(存儲類型屬性、計算類型屬性)

26. swift 中如何使用單例模式?

能夠經過類型屬性+let+private 來寫單例; 代碼以下以下:

public class FileManager {
    public static let shared = {
        // ....
        // ....
        return FileManager()
}()
    private init() { }
}
複製代碼

27.swift 中的下標是什麼?

  • 使用subscript能夠給任意類型(枚舉、結構體、類)增長下標功能,有些地方也翻譯爲:下標腳本
  • subscript的語法相似於實例方法、計算屬性,本質就是方法(函數)

使用以下:

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
複製代碼

27.簡要說明Swift中的初始化器?

  • 類、結構體、枚舉均可以定義初始化器
  • 類有2種初始化器: 指定初始化器(designated initializer)便捷初始化器(convenience initializer)
// 指定初始化器 
init(parameters) {
    statements 
}
// 便捷初始化器
convenience init(parameters) {
    statements 
} 
複製代碼

規則:

  • 每一個類至少有一個指定初始化器,指定初始化器是類的主要初始化器
  • 默認初始化器老是類的指定初始化器
  • 類偏向於少許指定初始化器,一個類一般只有一個指定初始化器

初始化器的相互調用規則

  • 指定初始化器必須從它的直系父類調用指定初始化器
  • 便捷初始化器必須從相同的類裏調用另外一個初始化器
  • 便捷初始化器最終必須調用一個指定初始化器

28.什麼可選鏈?

可選鏈是一個調用和查詢可選屬性、方法和下標的過程,它可能爲 nil 。若是可選項包含值,屬性、方法或者下標的調用成功;若是可選項是 nil ,屬性、方法或者下標的調用會返回 nil 。多個查詢能夠連接在一塊兒,若是鏈中任何一個節點是 nil ,那麼整個鏈就會得體地失敗。

  • 多個?能夠連接在一塊兒
  • 若是鏈中任何一個節點是nil,那麼整個鏈就會調用失敗

29. 什麼是運算符重載(Operator Overload)?

類、結構體、枚舉能夠爲現有的運算符提供自定義的實現,這個操做叫作:運算符重載

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複製代碼

其實呢做爲一個開發者,有一個學習的氛圍跟一個交流圈子特別重要,這是個人微信 你們有興趣能夠添加 邀請小夥伴們進入微信羣裏一塊兒 交流(想要加羣的能夠直接點擊此處進交流羣 來一塊兒交)

相關文章
相關標籤/搜索