數(shù)據(jù)結(jié)構(gòu)
Array
關(guān)于Swift的數(shù)組扳炬,有三種不同的形式:
- ContiguousArray: 其實(shí)我之前也一直沒有注意這個(gè)形式的數(shù)組吏颖,因?yàn)槠綍r(shí)更多在寫ObjC,很少寫Swift恨樟。ContiguousArray就是強(qiáng)制規(guī)劃一個(gè)連續(xù)的空間來儲(chǔ)存Elements半醉。當(dāng)用ContiguousArray來儲(chǔ)存對(duì)象數(shù)據(jù)(class或@objc)時(shí),其性能優(yōu)于Array劝术。
- Array: 當(dāng)Array儲(chǔ)存值類型的數(shù)據(jù)的時(shí)候缩多,內(nèi)存空間是連續(xù)的。但是當(dāng)儲(chǔ)存類型是對(duì)象(class或@objc)的時(shí)候养晋,Array會(huì)自動(dòng)橋接到NSArray上衬吆,內(nèi)存可能不連續(xù)。其實(shí)可以看出匙握,當(dāng)Array和ContiguousArray都儲(chǔ)存值類型(struct或enumeration)的話咆槽,他們的性能相當(dāng)。
- ArraySlice: 數(shù)組片段圈纺,它的作用就是讓我們更快和更高效地對(duì)一個(gè)大數(shù)組的其中一部分最處理秦忿。ArraySlice是不會(huì)創(chuàng)建新的存儲(chǔ)空間的,它和原本的Array在內(nèi)存上共享同一區(qū)域蛾娶。但是灯谣,這并不意味修改ArraySlice中的元素會(huì)影響到原來的Array。
ContiguousArray的創(chuàng)建:
var cArray = ContiguousArray<Any>(repeating: 0, count: 3)
print(type(of: cArray)) // "ContiguousArray<Any>\n"
Array的count和capacity:
我們知道蛔琅,當(dāng)Array中的元素增加的時(shí)候胎许,如果數(shù)組的內(nèi)存不足,就需要新建一個(gè)更大的數(shù)組,然后從舊的數(shù)組中復(fù)制所有元素到新的數(shù)組里」家ぃ現(xiàn)在的高級(jí)語(yǔ)言的Array都是Dynamic Array钩述,你不需要自己去給數(shù)組擴(kuò)容。為了提高數(shù)組擴(kuò)的容的效率穆碎,底層代碼都是成倍數(shù)的增加數(shù)組的大小牙勘。如Swift的Array的增長(zhǎng)因子是2(閱讀:https://blog.csdn.net/honglicu123/article/details/77541943)。所以Capacity和Count是不同的所禀,Capacity是指這個(gè)數(shù)組的總大小方面,Count是現(xiàn)在所有存在元素的個(gè)數(shù)。例子:
var cArray = ContiguousArray<Any>(repeating: 0, count: 3)
print(cArray.count) // 3
print(cArray.capacity) // 3
cArray.append(9)
print(cArray.count) // 4
print(cArray.capacity) // 6
// 當(dāng)removeAll的時(shí)候色徘,數(shù)組的所有空間都會(huì)被釋放掉
cArray.removeAll()
print(cArray.count) // 0
print(cArray.capacity) // 0
Array的reserveCapacity(_:):
正如上面所說恭金,當(dāng)數(shù)組擴(kuò)容的時(shí)候是有性能損耗的。當(dāng)你大概知道需要多大內(nèi)存容量的數(shù)組的時(shí)候褂策,就可以用reserveCapacity(_:)來創(chuàng)建和保持?jǐn)?shù)組的大小横腿,省去數(shù)組Capacity變化帶來的性能損耗。
ArraySlice的index并不總是開始于0:
ArraySlice會(huì)保留在原本數(shù)組中相同元素的index辙培。
let absences = [0, 2, 0, 4, 0, 3, 1, 0]
let midpoint = absences.count / 2
//
let firstHalf = absences[..<midpoint]
let secondHalf = absences[midpoint...]
firstHalf[0] // 0
secondHalf[0] // Fatal error: Index out of bounds
ArraySlice會(huì)持有一個(gè)對(duì)原數(shù)組的強(qiáng)應(yīng)用:
這意味著可能存在的內(nèi)存溢出蔑水。在Swift文檔中有如下建議:
Important: Long-term storage of ArraySlice
instances is discouraged. A slice holds a reference to the entire storage of a larger array, not just to the portion it presents, even after the original array's lifetime ends. Long-term storage of a slice may therefore prolong the lifetime of elements that are no longer otherwise accessible, which can appear to be memory and object leakage.
當(dāng)對(duì)ArraySlice做修改的時(shí)候,會(huì)影響到原數(shù)組嗎:
雖然在前面說到扬蕊,ArraySlice會(huì)持有一個(gè)對(duì)原數(shù)組的強(qiáng)應(yīng)用搀别,且ArraySlice是原數(shù)組中一個(gè)片段的映射(不知道映射這個(gè)解釋合不合適),也就是ArraySlice共享了原數(shù)組片段的內(nèi)存地址尾抑。但是歇父,答案是不會(huì)的。這是因?yàn)镾wift做好了Copy-on-write再愈,ArraySlice和原Array中榜苫,任何一個(gè)有改變,都會(huì)copy一個(gè)備份做改變翎冲。
Set and Dictionary
Set和Dictionary在查找上都是O(1)垂睬,這是源于他們都采用了hash。他們?cè)诖鎯?chǔ)時(shí)都是無序的抗悍。如果你有需求將一個(gè)自定義的類放入Set中或作為Dictionary的Key驹饺,那么這個(gè)類需要滿足Hashable Protocal。
Dictionary的value可以為nil嗎:
可以的缴渊。當(dāng)你在創(chuàng)建一個(gè)dictionary的時(shí)候赏壹,如果value為nil,則這個(gè)字典中所有的value都會(huì)轉(zhuǎn)化為optional衔沼。
另外蝌借,我們知道在Swift中去刪除一個(gè)Key-Value pair昔瞧,我們只需要給這個(gè)key所對(duì)應(yīng)的value賦值nil。那么當(dāng)value為nil時(shí)菩佑,這個(gè)方法會(huì)不會(huì)失效自晰?答案是不會(huì)。
最后擎鸠,當(dāng)一個(gè)value是nil的時(shí)候缀磕,用if let判斷時(shí)會(huì)怎樣缘圈?答案是if let會(huì)通過劣光,value為nil。例子:
var dic = ["a": 1,
"b": nil,
"c": 3]
var dicA = ["a": 1,
"b": 2,
"c": 3]
print(dic) // ["b": nil, "a": Optional(1), "c": Optional(3)]
print(dicA) // ["b": 2, "a": 1, "c": 3]
// if let
if let valueFromB = dic["b"] {
print("b has value: \(valueFromB)")
} else {
print("b has no value")
}
// 輸出: b has value: nil
// 刪除b
dic["b"] = nil
print(dic) // ["a": Optional(1), "c": Optional(3)]
String
對(duì)比與Objective-C糟把,swift把很多類都變成了struct绢涡,字符串也不例外。這樣的好處是增加了代碼的安全遣疯,因?yàn)镾wift為你做好了Copy-on-write雄可,你也不用再像寫ObjC那樣要特別留意用copy關(guān)鍵字和動(dòng)不動(dòng)就要copy一下。當(dāng)然缠犀,通過用inout關(guān)鍵字也是能實(shí)現(xiàn)傳遞引用的数苫。
獲得所有字符:
用一個(gè)Array來獲得一個(gè)所有字符的數(shù)組。
let string = "abc" // "abc"
let chars = Array(string) // ["a", "b", "c"]
subString:
String和Array很像辨液,當(dāng)你計(jì)算出一個(gè)range后虐急,你就可以獲得子字符串。
let fqdn = "useyourloaf.com"
let tldEndIndex = fqdn.endIndex
let tldStartIndex = fqdn.index(tldEndIndex, offsetBy: -3)
let range = Range(uncheckedBounds: (lower: tldStartIndex, upper: tldEndIndex))
fqdn[range] // "com"
“From https://useyourloaf.com/blog/swift-string-cheat-sheet/”
Reference:
https://xiaozhuanlan.com/ios-interview 故胤道長(zhǎng)和唐巧兩位大神的書《iOS 面試之道》
https://useyourloaf.com
https://swiftdoc.org/