前言:
最近把 iOS 面試中可能會遇到的問題整理了一番, 題目大部分是網(wǎng)上收錄的, 方便自己鞏固復習, 也分享給大家别伏; 希望對大家有所幫助码秉!
- 對于答案吆录,不一定都合適诱担,歡迎大家積極討論毡证;整理不易,如果您覺得還不錯蔫仙,麻煩在文末 “點個贊” 料睛,或者留下您的評論“Mark” 一下,謝謝您的支持
目錄合集
- iOS面試題--面試常問問題(一)
- iOS面試題--面試常問問題(二)
- iOS面試題--面試常問問題(三)
- iOS面試題--常問UI問題(四)
- iOS面試題--常問內(nèi)存管理問題(五)
- iOS面試題--常問多線程問題(六)
- iOS面試題--網(wǎng)絡相關(guān)問題(七)
- iOS面試題--常問Swift問題(八)
iOS面試題-常問Swift問題(八)
1. 介紹一下 Swift?
Swift
是蘋果在2014年6月WWDC發(fā)布的全新編程語言摇邦,借鑒了JS,Python,C#,Ruby
等語言特性,看上去偏腳本化,Swift 仍支持 cocoa touch
框架
他的優(yōu)點:
- Swift更加安全恤煞,它是類型安全的語言。
- Swift容易閱讀施籍,語法和文件結(jié)構(gòu)簡易化居扒。
- Swift更易于維護,文件分離后結(jié)構(gòu)更清晰丑慎。
- Swift代碼更少喜喂,簡潔的語法,可以省去大量冗余代碼
- Swift速度更快立哑,運算性能更高夜惭。
2. Swift 和OC 如何相互調(diào)用?
Swift 調(diào)用 OC代碼
需要創(chuàng)建一個Target-BriBridging-Header.h
的橋文件,在喬文件導入需要調(diào)用的OC代碼頭文件即可OC 調(diào)用 Swift代碼
直接導入Target-Swift.h
文件即可, Swift如果需要被OC調(diào)用,需要使用@objc 對方法或者屬性進行修飾
3. 類(class) 和 結(jié)構(gòu)體(struct) 有什么區(qū)別?
在 Swift 中,class 是引用類型(指針類型), struct 是值類型
值類型
- 值類型在傳遞和賦值時將進行復制; 賦值給var、let或者給函數(shù)傳參铛绰,是直接將所有內(nèi)容拷貝一份, 類似于對文件進行copy诈茧、paste操作,產(chǎn)生了全新的文件副本捂掰。屬于深拷貝(deep copy)
- 值類型: 比如結(jié)構(gòu)體,枚舉,是在椄一幔空間上存儲和操作的
引用類型
- 引用類型只會使用引用對象的一個"指向"; 賦值給var曾沈、let或者給函數(shù)傳參,是將內(nèi)存地址拷貝一份,類似于制作一個文件的替身(快捷方式鸥昏、鏈接)塞俱,指向的是同一個文件。屬于淺拷貝(shallow copy)
- 引用類型: 比如 Class,是在堆空間上存儲和操作的
4. class 和 struct 比較,優(yōu)缺點?
class 有以下功能,struct 是沒有的:
- class可以繼承,子類可以使用父類的特性和方法
- 類型轉(zhuǎn)換可以在運行時檢查和解釋一個實例對象
- class可以用 deinit來釋放資源
- 一個類可以被多次引用
struct 優(yōu)勢:
- 結(jié)構(gòu)較小,適用于復制操作,相比較一個class 實例被多次引用,struct 更安全
- 無需擔心內(nèi)存泄露問題
精選大廠 · iOS面試題答案PDF文集
- 獲取加小編的iOS技術(shù)交流圈:937 194 184吏垮,直接獲取
5. Swift 中,什么可選型(Optional)
- 在 Swift 中,可選型是為了表達一個變量為空的情況,當一個變量為空,他的值就是 nil
- 在類型名稱后面加個問號? 來定義一個可選型
- 值類型或者引用類型都可以是可選型變量
var name: String? // 默認為 nil
var age: Int? // 默認為nil
print(name, age) // 打印 nil, nil
6.Swift,什么是泛型?
- 泛型主要是為增加代碼的靈活性而生的,它可以是對應的代碼滿足任意類型的的變量或方法;
- 泛型可以將類型參數(shù)化障涯,提高代碼復用率,減少代碼量
// 實現(xiàn)一個方法,可以交換實現(xiàn)任意類型
func swap<T>(a: inout T, b: inout T) {
(a, b) = (b, a)
}
7. 訪問控制關(guān)鍵字 open, public, internal, fileprivate, private 的區(qū)別?
Swift 中有個5個級別的訪問控制權(quán)限,從高到低依次是 open, public, internal, fileprivate, private
它們遵循的基本規(guī)則: 高級別的變量不允許被定義為低級別變量的成員變量,比如一個 private 的 class 內(nèi)部允許包含 public的 String值,反之低級變量可以定義在高級別變量中;
- open: 具備最高訪問權(quán)限,其修飾的類可以和方法,可以在任意 模塊中被訪問和重寫.
- public: 權(quán)限僅次于 open膳汪,和 open 唯一的區(qū)別是: 不允許其他模塊進行繼承唯蝶、重寫
- internal: 默認權(quán)限, 只允許在當前的模塊中訪問,可以繼承和重寫,不允許在其他模塊中訪問
- fileprivate: 修飾的對象只允許在當前的文件中訪問;
- private: 最低級別訪問權(quán)限,只允許在定義的作用域內(nèi)訪問
8.關(guān)鍵字:Strong,Weak,Unowned 區(qū)別?
Swift 的內(nèi)存管理機制同OC一致,都是ARC管理機制; Strong,和 Weak用法同OC一樣
Unowned(無主引用), 不會產(chǎn)生強引用遗嗽,實例銷毀后仍然存儲著實例的內(nèi)存地址(類似于OC中的unsafe_unretained), 試圖在實例銷毀后訪問無主引用粘我,會產(chǎn)生運行時錯誤(野指針)
9. 如何理解copy-on-write?
值類型(比如:struct),在復制時,復制對象與原對象實際上在內(nèi)存中指向同一個對象,當且僅當修改復制的對象時,才會在內(nèi)存中創(chuàng)建一個新的對象,
- 為了提升性能,Struct, String痹换、Array征字、Dictionary、Set采取了Copy On Write的技術(shù)
- 比如僅當有“寫”操作時娇豫,才會真正執(zhí)行拷貝操作
- 對于標準庫值類型的賦值操作匙姜,Swift 能確保最佳性能,所有沒必要為了保證最佳性能來避免賦值
10.什么是屬性觀察?
屬性觀察是指在當前類型內(nèi)對特性屬性進行監(jiān)測,并作出響應,屬性觀察是 swift 中的特性,具有2種, willset
和 didset
var title: String {
willSet {
print("willSet", newValue)
}
didSet {
print("didSet", oldValue, title)
}
}
- willSet會傳遞新值锤躁,默認叫newValue
- didSet會傳遞舊值搁料,默認叫oldValue
- 在初始化器中設置屬性值不會觸發(fā)willSet和didSet
11. swift 為什么將 String,Array,Dictionary設計為值類型?
- 值類型和引用類型相比,最大優(yōu)勢可以高效的使用內(nèi)存,值類型在棧上操作,引用類型在堆上操作,棧上操作僅僅是單個指針的移動,而堆上操作牽涉到合并,位移,重鏈接,Swift 這樣設計減少了堆上內(nèi)存分配和回收次數(shù),使用 copy-on-write將值傳遞與復制開銷降到最低
12.如何將Swift 中的協(xié)議(protocol)中的部分方法設計為可選(optional)?
- 在協(xié)議和方法前面添加
@objc
,然后在方法前面添加optional
關(guān)鍵字,改方式實際上是將協(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")
}
}
13.比較Swift 和OC中的初始化方法 (init) 有什么不同?
swift 的初始化方法,更加嚴格和準確, swift初始化方法需要保證所有的非optional
的成員變量都完成初始化, 同時 swfit 新增了convenience和 required
兩個修飾初始化器的關(guān)鍵字
- convenience只提供一種方便的初始化器,必須通過一個指定初始化器來完成初始化
- required是強制子類重寫父類中所修飾的初始化方法
14.比較 Swift和OC中的 protocol 有什么不同?
- Swift 和OC中的 protocol相同點在于: 兩者都可以被用作代理;
- 不同點: Swift中的 protocol還可以對接口進行抽象,可以實現(xiàn)面向協(xié)議,從而大大提高編程效率,Swift中的protocol可以用于值類型,結(jié)構(gòu)體,枚舉;
精選大廠 · iOS面試題答案PDF文集
- 獲取加小編的iOS技術(shù)交流圈:937 194 184或详,直接獲取
15.swift 和OC 中的自省 有什么區(qū)別?
自省在OC中就是判斷某一對象是否屬于某一個類的操作,有以下2中方式
[obj iskinOfClass:[SomeClass class]]
[obj isMemberOfClass:[SomeClass class]]
在 Swift 中由于很多 class 并非繼承自 NSObject, 故而 Swift 使用 is
來判斷是否屬于某一類型, is
不僅可以作用于class
, 還是作用于enum
和struct
16.什么是函數(shù)重載? swift 支不支持函數(shù)重載?
- 函數(shù)重載是指: 函數(shù)名稱相同,函數(shù)的參數(shù)個數(shù)不同, 或者參數(shù)類型不同,或參數(shù)標簽不同, 返回值類型與函數(shù)重載無關(guān)
- swift 支持函數(shù)重載
17.swift 中的枚舉,關(guān)聯(lián)值 和 原始值的區(qū)分?
-
關(guān)聯(lián)值--有時會將枚舉的成員值跟其他類型的變量關(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" }
18. swift 中的閉包結(jié)構(gòu)是什么樣子的?
{
(參數(shù)列表) -> 返回值類型 in 函數(shù)體代碼
}
19. 什么是尾隨閉包?
- 將一個很長的閉包表達式作為函數(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
}
20. 什么是逃逸閉包?
當閉包作為一個實際參數(shù)傳遞給一個函數(shù)或者變量的時候霸琴,我們就說這個閉包逃逸了椒振,可以在形式參數(shù)前寫 @escaping
來明確閉包是允許逃逸的。
- 非逃逸閉包梧乘、逃逸閉包澎迎,一般都是當做參數(shù)傳遞給函數(shù)
- 非逃逸閉包:閉包調(diào)用發(fā)生在函數(shù)結(jié)束前,閉包調(diào)用在函數(shù)作用域內(nèi)
- 逃逸閉包:閉包有可能在函數(shù)結(jié)束后調(diào)用选调,閉包調(diào)用逃離了函數(shù)的作用域夹供,需要通過@escaping聲明
// 定義一個數(shù)組用于存儲閉包類型
var completionHandlers: [() -> Void] = []
// 在方法中將閉包當做實際參數(shù),存儲到外部變量中
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
如果你不標記函數(shù)的形式參數(shù)為 @escaping ,你就會遇到編譯時錯誤仁堪。
21. 什么是自動閉包?
自動閉包是一種自動創(chuàng)建的用來把作為實際參數(shù)傳遞給函數(shù)的表達式打包的閉包哮洽。它不接受任何實際參數(shù),并且當它被調(diào)用時弦聂,它會返回內(nèi)部打包的表達式的值鸟辅。這個語法的好處在于通過寫普通表達式代替顯式閉包而使你省略包圍函數(shù)形式參數(shù)的括號氛什。
func getFirstPositive(_ v1: Int, _ v2: @autoclosure () -> Int) -> Int? {
return v1 > 0 ? v1 : v2()
}
getFirstPositive(10, 20)
- 為了避免與期望沖突,使用了@autoclosure的地方最好明確注釋清楚:這個值會被推遲執(zhí)行
- @autoclosure 會自動將 20 封裝成閉包 { 20 }
- @autoclosure 只支持 () -> T 格式的參數(shù)
- @autoclosure 并非只支持最后1個參數(shù)
- 有@autoclosure匪凉、無@autoclosure枪眉,構(gòu)成了函數(shù)重載
如果你想要自動閉包允許逃逸,就同時使用 @autoclosure 和 @escaping 標志再层。
22. swift中, 存儲屬性和計算屬性的區(qū)別?
Swift中跟實例對象相關(guān)的屬性可以分為2大類
存儲屬性(Stored Property)
- 類似于成員變量這個概念
- 存儲在實例對象的內(nèi)存中
- 結(jié)構(gòu)體贸铜、類可以定義存儲屬性
- 枚舉不可以定義存儲屬性
計算屬性(Computed Property)
- 本質(zhì)就是方法(函數(shù))
- 不占用實例對象的內(nèi)存
- 枚舉、結(jié)構(gòu)體聂受、類都可以定義計算屬性
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存儲屬性設置屬性觀察器,通過關(guān)鍵字willSet
和didSet
來監(jiān)聽屬性變化
struct Circle {
var radius: Double {
willSet {
print("willSet", newValue)
}
didSet {
print("didSet", oldValue, radius)
}
}
init() {
self.radius = 1.0
print("Circle init!")
}
}
精選大廠 · iOS面試題答案PDF文集
- 獲取加小編的iOS技術(shù)交流圈:937 194 184饺饭,直接獲取
25. swift中什么類型屬性(Type Property)?
嚴格來說渤早,屬性可以分為
實例屬性(Instance Property): 只能通過實例對象去訪問
- 存儲實例屬性(Stored Instance Property):存儲在實例對象的內(nèi)存中,每個實例對象都有1份
- 計算實例屬性(Computed Instance Property)
類型屬性(Type Property):只能通過類型去訪問
- 存儲類型屬性(Stored Type Property):整個程序運行過程中瘫俊,就只有1份內(nèi)存(類似于全局變量)
- 計算類型屬性(Computed Type Property)
可以通過static定義類型屬性 p如果是類鹊杖,也可以用關(guān)鍵字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可以給任意類型(枚舉川尖、結(jié)構(gòu)體登下、類)增加下標功能,有些地方也翻譯為:下標腳本
- subscript的語法類似于實例方法叮喳、計算屬性被芳,本質(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
27.簡要說明Swift中的初始化器?
- 類、結(jié)構(gòu)體馍悟、枚舉都可以定義初始化器
- 類有2種初始化器:
指定初始化器(designated initializer)
畔濒、便捷初始化器(convenience initializer)
// 指定初始化器
init(parameters) {
statements
}
// 便捷初始化器
convenience init(parameters) {
statements
}
規(guī)則:
- 每個類至少有一個指定初始化器,指定初始化器是類的主要初始化器
- 默認初始化器總是類的指定初始化器
- 類偏向于少量指定初始化器锣咒,一個類通常只有一個指定初始化器
初始化器的相互調(diào)用規(guī)則
- 指定初始化器必須從它的直系父類調(diào)用指定初始化器
- 便捷初始化器必須從相同的類里調(diào)用另一個初始化器
- 便捷初始化器最終必須調(diào)用一個指定初始化器
28.什么可選鏈?
可選鏈是一個調(diào)用和查詢可選屬性侵状、方法和下標的過程,它可能為 nil 毅整。如果可選項包含值趣兄,屬性、方法或者下標的調(diào)用成功悼嫉;如果可選項是 nil 艇潭,屬性、方法或者下標的調(diào)用會返回 nil 。多個查詢可以鏈接在一起暴区,如果鏈中任何一個節(jié)點是 nil 闯团,那么整個鏈就會得體地失敗。
- 多個?可以鏈接在一起
- 如果鏈中任何一個節(jié)點是nil仙粱,那么整個鏈就會調(diào)用失敗
29. 什么是運算符重載(Operator Overload)?
類房交、結(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
收錄 | 原文地址
結(jié)語
再次說一聲候味,對于答案,不一定都合適隔心,歡迎大家積極討論白群;整理不易,如果您覺得還不錯硬霍,麻煩在文末 “點個贊” 帜慢,或者留下您的評論“Mark” 一下,謝謝您的支持