Swift面試篇

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、@objcdynamic的函數(shù)消息派發(fā)
初始聲明函數(shù)使用函數(shù)表派發(fā)
泛型/元組/高階函數(shù) 輕量,如集合類型 泛型可以使我們在程序代碼中定義一些可變的部分,在運行的時候指定
元組是多個值組合成一個復合值,且值可以是任意類型
高階函數(shù)的參數(shù)或者返回值為函數(shù)
語言效率 性能更高,速度更快 Swift靜態(tài)編譯以及Option類型相對安全
語法簡潔、面向協(xié)議、高度抽象的泛型性能更高
值類型在??臻g單指針處理性能更快
文件特性 .swift 單文件 .h/.m包含頭文件 Swift中通過Open、Public、Internal、FilePrivatePirvate來實現(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的成員變量都完成初始化, 同時新增了conveniencerequired
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")
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容