一些優(yōu)質(zhì)的面試題匯總
為了方便自己的基礎(chǔ)知識(shí)積累苫耸,我這里只是摘抄
1、private
private訪問(wèn)級(jí)別所修飾的屬性或者方法只能在當(dāng)前類(lèi)里訪問(wèn)乐尊。
2、fileprivate
fileprivate訪問(wèn)級(jí)別所修飾的屬性或者方法在當(dāng)前的Swift源文件里可以訪問(wèn)。
3、internal(默認(rèn)訪問(wèn)級(jí)別邮辽,internal修飾符可寫(xiě)可不寫(xiě))
internal訪問(wèn)級(jí)別所修飾的屬性或方法在源代碼所在的整個(gè)模塊都可以訪問(wèn)。
如果是框架或者庫(kù)代碼贸营,則在整個(gè)框架內(nèi)部都可以訪問(wèn)吨述,框架由外部代碼所引用時(shí),則不可以訪問(wèn)钞脂。
如果是App代碼揣云,也是在整個(gè)App代碼,也是在整個(gè)App內(nèi)部可以訪問(wèn)冰啃。
4邓夕、public
可以被任何人訪問(wèn)。但其他module中不可以被override和繼承阎毅,而在module內(nèi)可以被override和繼承焚刚。
5,open
可以被任何人使用扇调,包括override和繼承矿咕。
訪問(wèn)順序:
現(xiàn)在的訪問(wèn)權(quán)限則依次為:open,public,internal碳柱,fileprivate捡絮,private。
#一莲镣、open與public的區(qū)別
public:可以別任何人訪問(wèn)福稳,但是不可以被其他module復(fù)寫(xiě)和繼承。
open:可以被任何人訪問(wèn)剥悟,可以被繼承和復(fù)寫(xiě)灵寺。
#二曼库、struct與class 的區(qū)別
struct是值類(lèi)型区岗,class是引用類(lèi)型。
值類(lèi)型的變量直接包含它們的數(shù)據(jù)毁枯,對(duì)于值類(lèi)型都有它們自己的數(shù)據(jù)副本慈缔,因此對(duì)一個(gè)變量操作不可能影響另一個(gè)變量。
引用類(lèi)型的變量存儲(chǔ)對(duì)他們的數(shù)據(jù)引用种玛,因此后者稱(chēng)為對(duì)象藐鹤,因此對(duì)一個(gè)變量操作可能影響另一個(gè)變量所引用的對(duì)象。
二者的本質(zhì)區(qū)別:struct是深拷貝赂韵,拷貝的是內(nèi)容娱节;class是淺拷貝,拷貝的是指針祭示。
property的初始化不同:class 在初始化時(shí)不能直接把 property 放在 默認(rèn)的constructor 的參數(shù)里肄满,而是需要自己創(chuàng)建一個(gè)帶參數(shù)的constructor;而struct可以质涛,把屬性放在默認(rèn)的constructor 的參數(shù)里稠歉。
變量賦值方式不同:struct是值拷貝;class是引用拷貝汇陆。
immutable變量:swift的可變內(nèi)容和不可變內(nèi)容用var和let來(lái)甄別怒炸,如果初始為let的變量再去修改會(huì)發(fā)生編譯錯(cuò)誤。struct遵循這一特性毡代;class不存在這樣的問(wèn)題阅羹。
mutating function: struct 和 class 的差別是 struct 的 function 要去改變 property 的值的時(shí)候要加上 mutating,而 class 不用教寂。
# Swift mutating關(guān)鍵字的使用灯蝴?
默認(rèn)情況下,不能在實(shí)例方法中修改值類(lèi)型的屬性.若在實(shí)例方法中使用 mutating 關(guān)鍵字,
不僅可以在實(shí)例方法中修改值類(lèi)型的屬性,而且會(huì)在方法實(shí)現(xiàn)結(jié)束時(shí)將其寫(xiě)回到原始結(jié)構(gòu).
繼承: struct不可以繼承,class可以繼承孝宗。
struct比class更輕量:struct分配在棧中穷躁,class分配在堆中。
#三、swift把struct作為數(shù)據(jù)模型
3.1優(yōu)點(diǎn)
安全性: 因?yàn)?Struct 是用值類(lèi)型傳遞的问潭,它們沒(méi)有引用計(jì)數(shù)猿诸。
內(nèi)存: 由于他們沒(méi)有引用數(shù),他們不會(huì)因?yàn)檠h(huán)引用導(dǎo)致內(nèi)存泄漏狡忙。
速度: 值類(lèi)型通常來(lái)說(shuō)是以棧的形式分配的梳虽,而不是用堆。因此他們比 Class 要快很多!
拷貝:Objective-C 里拷貝一個(gè)對(duì)象,你必須選用正確的拷貝類(lèi)型(深拷貝灾茁、淺拷貝),而值類(lèi)型的拷貝則非常輕松窜觉!
線(xiàn)程安全: 值類(lèi)型是自動(dòng)線(xiàn)程安全的。無(wú)論你從哪個(gè)線(xiàn)程去訪問(wèn)你的 Struct 北专,都非常簡(jiǎn)單禀挫。
3.2 缺點(diǎn)
Objective-C與swift混合開(kāi)發(fā):OC調(diào)用的swift代碼必須繼承于NSObject。
繼承:struct不能相互繼承拓颓。
NSUserDefaults:Struct 不能被序列化成 NSData 對(duì)象
1. 說(shuō)說(shuō)Swift為什么將String,Array,Dictionary設(shè)計(jì)成值類(lèi)型语婴?
值類(lèi)型相比引用類(lèi)型,最大的優(yōu)勢(shì)在于內(nèi)存使用的高效.值類(lèi)型在棧上操作,引用類(lèi)型在堆上操作.
棧上的操作僅僅是單個(gè)指針的上下移動(dòng),而堆上的操作則牽涉到合并、移位驶睦、重新鏈接等.
也就是說(shuō)Swift這樣設(shè)計(jì),大幅減少了堆上的內(nèi)存分配和回收的次數(shù).
同時(shí)寫(xiě)時(shí)復(fù)制又將值傳遞和復(fù)制的開(kāi)銷(xiāo)降到了最低.
String,Array,Dictionary設(shè)計(jì)成值類(lèi)型,也是為了線(xiàn)程安全考慮.
通過(guò)Swift的let設(shè)置,使得這些數(shù)據(jù)達(dá)到了真正意義上的“不變”,
它也從根本上解決了多線(xiàn)程中內(nèi)存訪問(wèn)和操作順序的問(wèn)題.
設(shè)計(jì)成值類(lèi)型還可以提升API的靈活度.
2.autoclosure 的作用
自動(dòng)閉包砰左,將參數(shù)自動(dòng)封裝為閉包參數(shù)
2.1 swift中 closure 與OC中block的區(qū)別?
1场航、closure是匿名函數(shù)缠导、block是一個(gè)結(jié)構(gòu)體對(duì)象
2、block內(nèi)部會(huì)對(duì)值類(lèi)型做一份復(fù)制溉痢,并不指向之前的值的內(nèi)存地址僻造,
而對(duì)于對(duì)象類(lèi)型則會(huì)指向?qū)ο螽?dāng)前的內(nèi)存地址,
所以修改number時(shí)适室,block里的number數(shù)值不變嫡意,而修改字符串時(shí),
block里的字符串則改變了捣辆;
closure則默認(rèn)給外部訪問(wèn)的變量加上了__block修飾詞的block蔬螟。
3. swift中,如何阻止方法,屬性,下標(biāo)被子類(lèi)改寫(xiě)?
在類(lèi)的定義中使用 final 關(guān)鍵字聲明類(lèi)、屬性汽畴、方法和下標(biāo)旧巾。
final 聲明的類(lèi)不能被繼承,final 聲明的屬性忍些、方法和下標(biāo)不能被重寫(xiě)鲁猩。
如果只是限制一個(gè)方法或?qū)傩员恢貙?xiě),只需要在該方法或者屬性前加一個(gè) final.
如果需要限制整個(gè)類(lèi)無(wú)法被繼承, 那么可以在類(lèi)名之前加一個(gè)final。
4. associatedtype 的作用
關(guān)聯(lián)類(lèi)型: 為協(xié)議中的某個(gè)類(lèi)型提供了一個(gè)別名,其代表的真實(shí)類(lèi)型在實(shí)現(xiàn)者中定義.
//協(xié)議罢坝,使用關(guān)聯(lián)類(lèi)型
protocol TableViewCell {
associatedtype T
func updateCell(_ data: T)
}
//遵守TableViewCell
class MyTableViewCell: UITableViewCell, TableViewCell {
typealias T = Model
func updateCell(_ data: Model) {
// do something ...
}
}
5.什么是泛型,swift在哪些地方使用了泛型廓握?
泛型(generic)可以使我們?cè)诔绦虼a中定義一些可變的部分,在運(yùn)行的時(shí)候指定。
使用泛型可以最大限度地重用代碼隙券、保護(hù)類(lèi)型的安全以及提高性能男应。
6. map、filter娱仔、reduce 的作用
map 用于映射, 可以將一個(gè)列表轉(zhuǎn)換為另一個(gè)列表
[1, 2, 3].map{"\($0)"}// 數(shù)字?jǐn)?shù)組轉(zhuǎn)換為字符串?dāng)?shù)組
["1", "2", "3"]
filter 用于過(guò)濾, 可以篩選出想要的元素
[1, 2, 3].filter{$0 % 2 == 0} // 篩選偶數(shù)
// [2]
reduce 合并
[1, 2, 3].reduce(""){$0 + "\($1)"}// 轉(zhuǎn)換為字符串并拼接
// "123"
7. map 與 flatmap 的區(qū)別
1. map 可以對(duì)一個(gè)集合類(lèi)型的所有元素做一個(gè)映射操作.
2. flatMap
第一個(gè)作用和map一樣,對(duì)一個(gè)集合類(lèi)型的所有元素做一個(gè)映射操作,且可以過(guò)濾為nil的情況.
例如:
let array = [1,2,5,6,7,nil]
let array_map = array.map { $0 }
//[Optional(1), Optional(2), Optional(5), Optional(6), Optional(7), nil]
let array_flatmap = array_map.flatMap { $0 }
//[1, 2, 5, 6, 7]
第二種情況可以進(jìn)行“降維”操作
let array = [["1", "2"],["3", "4"]]
let array_map = array.map { $0 }
//[["1", "2"], ["3", "4"]]
let array_flatmap = array_map.flatMap { $0 }
//["1", "2", "3", "4"]
8. defer沐飘、guard的作用?
defer 語(yǔ)句塊中的代碼, 會(huì)在當(dāng)前作用域結(jié)束前調(diào)用,無(wú)論函數(shù)是否會(huì)拋出錯(cuò)誤牲迫。
每當(dāng)一個(gè)作用域結(jié)束就進(jìn)行該作用域defer執(zhí)行耐朴。 如果有多個(gè) defer, 那么后加入的先執(zhí)行.
guard :過(guò)濾器,攔截器
guard 和 if 類(lèi)似, 不同的是, guard 總是有一個(gè) else 語(yǔ)句,
如果表達(dá)式是假或者值綁定失敗的時(shí)候, 會(huì)執(zhí)行 else 語(yǔ)句, 且在 else 語(yǔ)句中一定要停止函數(shù)調(diào)用.
9. throws 和 rethrows 的用法與作用
throws 用在函數(shù)上, 表示這個(gè)函數(shù)會(huì)拋出錯(cuò)誤.
有兩種情況會(huì)拋出錯(cuò)誤, 一種是直接使用 throw 拋出, 另一種是調(diào)用其他拋出異常的函數(shù)時(shí), 直接使用 try XX 沒(méi)有處理異常.
enum DivideError: Error {
case EqualZeroError;
}
func divide(_ a: Double, _ b: Double) throws -> Double {
guard b != Double(0) else {
throw DivideError.EqualZeroError
}
return a / b
}
func split(pieces: Int) throws -> Double {
return try divide(1, Double(pieces))
}
rethrows 與 throws 類(lèi)似, 不過(guò)只適用于參數(shù)中有函數(shù), 且函數(shù)會(huì)拋出異常的情況, rethrows 可以用 throws 替換, 反過(guò)來(lái)不行
func processNumber(a: Double, b: Double, function: (Double, Double) throws -> Double) rethrows -> Double {
return try function(a, b)
}
10.如何自定義下標(biāo)獲取
實(shí)現(xiàn) subscript 即可,索引除了數(shù)字之外, 其他類(lèi)型也是可以的
如:
extension AnyList {
subscript(index: Int) -> T{
return self.list[index]
}
subscript(indexString: String) -> T?{
guard let index = Int(indexString) else {
return nil
}
return self.list[index]
}
}
11. 為什么數(shù)組索引越界會(huì)崩潰盹憎,而字典用下標(biāo)取值時(shí) key 沒(méi)有對(duì)應(yīng)值的話(huà)返回的是 nil 不會(huì)崩潰筛峭。
1 數(shù)組索引訪問(wèn)的是一段連續(xù)地址,越界訪問(wèn)也能訪問(wèn)到內(nèi)存,但這段內(nèi)存不一定可用,所以會(huì)引起Crash.
2 字典的key并沒(méi)有對(duì)應(yīng)確定的內(nèi)存地址,所以是安全的.
struct Array<Element> {
subscript(index: Int) -> Element
}
struct Dictionary<Key: Hashable, Value> {
subscript(key: Key) -> Value?
}
問(wèn)題一: 下面代碼中變量 tutorial1.difficulty 和 tutorial2.difficulty 的值分別是什么? 如果 Tutorial 是一個(gè)類(lèi),會(huì)有什么不同嗎脚乡?為什么?
struct Tutorial {
var difficulty: Int = 1
}
var tutorial1 = Tutorial()
var tutorial2 = tutorial1
tutorial2.difficulty = 2
回答:
tutorial1.difficulty 等于 1, tutorial2.difficulty 等于 2.
swift中的結(jié)構(gòu)體是值類(lèi)型蜒滩。是按值類(lèi)型而不是引用類(lèi)型復(fù)制值的滨达。
創(chuàng)建了一個(gè)tutorial1的副本奶稠,并將其分配給tutorial2:
var tutorial2 = tutorial1
“ tutorial1 ”中未反映對(duì)“ tutorial12”的更改
如果 Tutorial 是一個(gè)類(lèi),那么 tutorial1 和 tutorial2 都等于 2.
swift中的類(lèi)是引用類(lèi)型捡遍。當(dāng)你更改Tutorial1的屬性時(shí)逊桦,你將看到它反映在Tutorial2中锅移,反之亦然。
問(wèn)題二: 你用var聲明了view1,用let聲明了view2以故。有什么區(qū)別,最后一行會(huì)編譯通過(guò)嗎艳狐?
import UIKit
var view1 = UIView()
view1.alpha = 0.5
let view2 = UIView()
view2.alpha = 0.5 // 此行是否編譯聘殖?
回答:
是的,最后一行可以編譯续挟。view1 是一個(gè)變量紧卒,可以給它重新分配一個(gè) UIView 類(lèi)型的新實(shí)例。使用let诗祸,只能分配一次值跑芳,因此不會(huì)編譯以下代碼:
view2 = view1 // Error: view2 is immutable
UIView是一個(gè)具有引用語(yǔ)義的類(lèi),因此你可以改變view2的屬性-這意味著最后一行將編譯:
let view2 = UIView()
view2.alpha = 0.5 // Yes!
問(wèn)題三: 這段復(fù)雜的代碼按字母順序?qū)γQ(chēng)數(shù)組進(jìn)行排序直颅。盡可能簡(jiǎn)化閉包博个。
var animals = ["fish", "cat", "chicken", "dog"]
animals.sort { (one: String, two: String) -> Bool in
return one < two
}
print(animals)
回答:
類(lèi)型推斷系統(tǒng)會(huì)自動(dòng)判斷閉包中參數(shù)的類(lèi)型和返回類(lèi)型,就可以去掉類(lèi)型:
animals.sort { (one, two) -> Bool in
return one < two
}
可以用$I符號(hào)替換參數(shù)名:
animals.sort { return $0 < $1 }
在單語(yǔ)句閉包中功偿,可以省略返回關(guān)鍵字盆佣。最后一條語(yǔ)句的值將成為閉包的返回值:
animals.sort { $0 < $1 }
后,由于Swift知道數(shù)組的元素符合equatable,因此可以簡(jiǎn)單地編寫(xiě):
animals.sort(by: <)
問(wèn)題四:此代碼創(chuàng)建兩個(gè)類(lèi):Address 和 Person 共耍。然后它創(chuàng)建兩個(gè) Person 實(shí)例來(lái)表示Ray和Brian投蝉。
class Address {
var fullAddress: String
var city: String
init(fullAddress: String, city: String) {
self.fullAddress = fullAddress
self.city = city
}
}
class Person {
var name: String
var address: Address
init(name: String, address: Address) {
self.name = name
self.address = address
}
}
var headquarters = Address(fullAddress: "123 Tutorial Street", city: "Appletown")
var ray = Person(name: "Ray", address: headquarters)
var brian = Person(name: "Brian", address: headquarters)
假設(shè)布 Brian 搬到街對(duì)面的新大樓,更新他的地址:
brian.address.fullAddress = "148 Tutorial Street"
它編譯,運(yùn)行時(shí)不會(huì)出錯(cuò)征堪。如果你現(xiàn)在查一下 Ray 的地址瘩缆,他也搬到了新大樓。
print (ray.address.fullAddress)
這是怎么回事佃蚜?你如何解決這個(gè)問(wèn)題庸娱?
回答:
Address 是一個(gè)類(lèi),是引用類(lèi)型谐算,不管是通過(guò)Ray還是Brian訪問(wèn)熟尉,都是相同的實(shí)例。更改 headquarters 地址將同時(shí)更改兩個(gè)人的地址洲脂。你能想象如果 Brian 收到Ray的郵件會(huì)發(fā)生什么情況嗎斤儿,反之亦然?
解決方案是創(chuàng)建一個(gè)新 Address 對(duì)象來(lái)分配給Brian恐锦,或者將 Address 聲明為結(jié)構(gòu)體往果。
口述問(wèn)題
1. 什么是可選的,可選可以解決哪些問(wèn)題一铅?
使用可選類(lèi)型(optionals)來(lái)處理值可能缺失的情況陕贮。在objective-c中,只有在使用nil特殊值的引用類(lèi)型中才可以表示值缺失潘飘。值類(lèi)型(如int或float)不具有此功能肮之。
Swift將缺乏值概念擴(kuò)展到引用類(lèi)型和值類(lèi)型〔仿迹可選變量可以包含值或零戈擒,表示是否缺少值。
總結(jié)結(jié)構(gòu)體和類(lèi)之間的主要區(qū)別艰毒。
差異總結(jié)為:
類(lèi)支持繼承筐高;結(jié)構(gòu)不支持。
類(lèi)是引用類(lèi)型现喳;結(jié)構(gòu)體是值類(lèi)型凯傲。
2.什么是通用類(lèi)型,它們解決了什么問(wèn)題嗦篱?
在swift中冰单,可以在函數(shù)和數(shù)據(jù)類(lèi)型中使用泛型,例如在類(lèi)灸促、結(jié)構(gòu)體或枚舉中诫欠。
泛型解決了代碼重復(fù)的問(wèn)題涵卵。當(dāng)有一個(gè)方法接受一種類(lèi)型的參數(shù)時(shí),通常會(huì)復(fù)制它以適應(yīng)不同類(lèi)型的參數(shù)荒叼。
例如轿偎,在下面的代碼中,第二個(gè)函數(shù)是第一個(gè)函數(shù)的“克隆”被廓,但它接受字符串而不是整數(shù)坏晦。
func areIntEqual(_ x: Int, _ y: Int) -> Bool {
return x == y
}
func areStringsEqual(_ x: String, _ y: String) -> Bool {
return x == y
}
areStringsEqual("ray", "ray") // true
areIntEqual(1, 1) // true
通過(guò)采用泛型,可以將這兩個(gè)函數(shù)合并為一個(gè)函數(shù)嫁乘,同時(shí)保持類(lèi)型安全昆婿。下面是通用實(shí)現(xiàn):
func areTheyEqual<T: Equatable>(_ x: T, _ y: T) -> Bool {
return x == y
}
areTheyEqual("ray", "ray")
areTheyEqual(1, 1)
由于在本例中測(cè)試的是相等性,所以將參數(shù)限制為遵守 Equatable 協(xié)議的任何類(lèi)型蜓斧。此代碼實(shí)現(xiàn)了預(yù)期的結(jié)果仓蛆,并防止傳遞不同類(lèi)型的參數(shù)。
3.在某些情況下挎春,你無(wú)法避免使用隱式展開(kāi)的選項(xiàng)看疙。什么時(shí)候?為什么直奋?
使用隱式展開(kāi)選項(xiàng)的最常見(jiàn)原因是:
如果在實(shí)例化時(shí)無(wú)法初始化非本質(zhì)的屬性能庆。
一個(gè)典型的例子是Interface Builder出口,它總是在它的所有者之后初始化帮碰。在這種特定情況下 - 假設(shè)它在Interface Builder中正確配置 - 你在使用它之前保證outlet是非零的相味。
解決強(qiáng)引用循環(huán)問(wèn)題拾积,即兩個(gè)實(shí)例相互引用并且需要對(duì)另一個(gè)實(shí)例的非空引用殉挽。在這種情況下,將一側(cè)標(biāo)記為無(wú)主引用拓巧,而另一側(cè)使用隱式解包可選斯碌。
打開(kāi)可選項(xiàng)的各種方法有哪些?他們?nèi)绾卧u(píng)價(jià)安全性肛度?
var x : String? = "Test"
提示:有七種方法傻唾。
強(qiáng)行打開(kāi) - 不安全。
let a: String = x!
隱式解包變量聲明 - 在許多情況下不安全承耿。
var a = x!
可選綁定 - 安全冠骄。
if let a = x {
print("x was successfully unwrapped and is = \(a)")
}
可選鏈接 - 安全。
let a = x?.count
無(wú)合并操作員 - 安全加袋。
let a = x ?? ""
警衛(wèi)聲明 - 安全凛辣。
guard let a = x else {
return
}
可選模式 - 安全。
if case let a? = x {
print(a)
}
中級(jí)
1. nil 和 .none有什么區(qū)別?
沒(méi)有區(qū)別职烧,因?yàn)镺ptional.none(簡(jiǎn)稱(chēng).none)和nil是等價(jià)的扁誓。
實(shí)際上防泵,下面的等式輸出為真:
nil == .none
使用nil更常見(jiàn),推薦使用蝗敢。
2.這是 thermometer 作為類(lèi)和結(jié)構(gòu)的模型捷泞。編譯器在最后一行報(bào)錯(cuò)。為什么編譯失斒偾础锁右?
public class ThermometerClass {
private(set) var temperature: Double = 0.0
public func registerTemperature(_ temperature: Double) {
self.temperature = temperature
}
}
let thermometerClass = ThermometerClass()
thermometerClass.registerTemperature(56.0)
public struct ThermometerStruct {
private(set) var temperature: Double = 0.0
public mutating func registerTemperature(_ temperature: Double) {
self.temperature = temperature
}
}
let thermometerStruct = ThermometerStruct()
thermometerStruct.registerTemperature(56.0)
使用可變函數(shù)正確聲明ThermometerStruct以更改其內(nèi)部變量temperature。編譯器報(bào)錯(cuò)是因?yàn)槟阍谕ㄟ^(guò) let 創(chuàng)建的實(shí)例上調(diào)用了registerTemperature讶泰,因?yàn)樗遣豢勺兊穆夂et改為var通過(guò)編譯。
對(duì)于結(jié)構(gòu)體峻厚,必須將內(nèi)部狀態(tài)更改為mutating的方法標(biāo)記响蕴,但不能從不可變變量中調(diào)用它們。
3.這段代碼會(huì)打印什么惠桃?為什么浦夷?
var thing = "cars"
let closure = { [thing] in
print("I love \(thing)")
}
thing = "airplanes"
closure()
它會(huì)打印:I love cars辜王。聲明閉包時(shí)劈狐,捕獲列表會(huì)創(chuàng)建一個(gè) thing 副本。這意味著即使為 thing 分配新值呐馆,捕獲的值也不會(huì)改變肥缔。
如果省略閉包中的捕獲列表,則編譯器使用引用而不是副本汹来。因此续膳,當(dāng)調(diào)用閉包時(shí),它會(huì)反映對(duì)變量的任何更改收班》夭恚可以在以下代碼中看到:
var thing = "cars"
let closure = {
print("I love \(thing)")
}
thing = "airplanes"
closure() // Prints: "I love airplanes"
4.這是一個(gè)全局函數(shù),用于計(jì)算數(shù)組中唯一值的數(shù)量:
func countUniques<T: Comparable>(_ array: Array<T>) -> Int {
let sorted = array.sorted()
let initial: (T?, Int) = (.none, 0)
let reduced = sorted.reduce(initial) {
($1, $0.0 == $1 ? $0.1 : $0.1 + 1)
}
return reduced.1
}
它使用sorted方法摔桦,因此它將T限制為符合Comparable協(xié)議的類(lèi)型社付。
你這樣調(diào)用它:
countUniques([1, 2, 3, 3]) // result is 3
問(wèn)題: 將此函數(shù)重寫(xiě)為Array上的擴(kuò)展方法,以便你可以編寫(xiě)如下內(nèi)容:
[1, 2, 3, 3].countUniques() // should print 3
你可以將全局countUniques(_ :)重寫(xiě)為Array擴(kuò)展:
extension Array where Element: Comparable {
func countUniques() -> Int {
let sortedValues = sorted()
let initial: (Element?, Int) = (.none, 0)
let reduced = sortedValues.reduce(initial) {
($1, $0.0 == $1 ? $0.1 : $0.1 + 1)
}
return reduced.1
}
}
請(qǐng)注意邻耕,僅當(dāng)泛型 Element 符合Comparable時(shí)鸥咖,新方法才可用。
5.這是 divide 對(duì)象的兩個(gè)可選 Double 類(lèi)型變量的方法兄世。在執(zhí)行實(shí)際解析之前啼辣,有三個(gè)先決條件需要驗(yàn)證:
1. 變量 dividend 必須包含非空的值
2. 變量 divisor 必須包含非空的值
3. 變量 divisor 不能等于零
func divide(_ dividend: Double?, by divisor: Double?) -> Double? {
if dividend == nil {
return nil
}
if divisor == nil {
return nil
}
if divisor == 0 {
return nil
}
return dividend! / divisor!
}
使用guard語(yǔ)句并且不使用強(qiáng)制解包來(lái)改進(jìn)此功能。
func divide(_ dividend: Double?, by divisor: Double?) -> Double? {
guard let dividend = dividend, let divisor = divisor, divisor != 0 else {
return nil
}
return dividend / divisor
}
6.使用 if let 重寫(xiě)第五題
func divide(_ dividend: Double?, by divisor: Double?) -> Double? {
if let dividend = dividend, let divisor = divisor, divisor != 0 {
return dividend / divisor
} else {
return nil
}
}
中級(jí)口述問(wèn)題
第一題
在Objective-C中碘饼,聲明一個(gè)這樣的常量:
const int number = 0;
Swift對(duì)應(yīng)的寫(xiě)法:
let number = 0
const是在編譯時(shí)使用值或表達(dá)式初始化的變量熙兔,必須在編譯時(shí)解析悲伶。
使用let創(chuàng)建的不可變是在運(yùn)行時(shí)確定的常量。你可以使用靜態(tài)或動(dòng)態(tài)表達(dá)式對(duì)其進(jìn)行初始化住涉。這允許聲明如下:
let higherNumber = number + 5
請(qǐng)注意麸锉,只能分配一次值。
第二題
聲明一個(gè) static 修飾的屬性或函數(shù)舆声,請(qǐng)?jiān)谥殿?lèi)型上使用static修飾符花沉。這是一個(gè)結(jié)構(gòu)的例子:你用 static 修飾值類(lèi)型。這是一個(gè)結(jié)構(gòu)體的例子:
struct Sun {
static func illuminate() {}
}
對(duì)于類(lèi)媳握,可以使用static或class修飾符碱屁。他們實(shí)現(xiàn)了相同的目標(biāo),但方式不同蛾找。你能解釋一下它們有何不同娩脾?
static 使屬性或方法為靜態(tài)并不可重寫(xiě)。使用class可以重寫(xiě)屬性或方法打毛。
應(yīng)用于類(lèi)時(shí)柿赊,static將成為class final的別名。
例如幻枉,在此代碼中碰声,當(dāng)你嘗試重寫(xiě) illuminate() 時(shí),編譯器會(huì)抱錯(cuò):
class Star {
class func spin() {}
static func illuminate() {}
}
class Sun : Star {
override class func spin() {
super.spin()
}
// error: class method overrides a 'final' class method
override static func illuminate() {
super.illuminate()
}
}
問(wèn)題三
你可以在 extension 里添加存儲(chǔ)屬性嗎熬甫?為什么行或不行呢胰挑?
不,這是不可能的椿肩。你可以使用擴(kuò)展來(lái)向現(xiàn)有類(lèi)型添加新行為瞻颂,但不能更改類(lèi)型本身或其接口。如果添加存儲(chǔ)的屬性覆旱,則需要額外的內(nèi)存來(lái)存儲(chǔ)新值蘸朋。擴(kuò)展程序無(wú)法管理此類(lèi)任務(wù)。
問(wèn)題四
Swift中的協(xié)議是什么扣唱?
協(xié)議是一種定義方法,屬性和其他要求藍(lán)圖的類(lèi)型团南。然后噪沙,類(lèi),結(jié)構(gòu)或枚舉可以遵守協(xié)議來(lái)實(shí)現(xiàn)這些要求吐根。
遵守協(xié)議需要實(shí)現(xiàn)該協(xié)議的要求正歼。該協(xié)議本身不實(shí)現(xiàn)任何功能,而是定義功能拷橘【忠澹可以擴(kuò)展協(xié)議以提供某些要求的默認(rèn)實(shí)現(xiàn)或符合類(lèi)型可以利用的其他功能喜爷。
高級(jí)書(shū)面問(wèn)題
第一題
思考以下 thermometer 模型結(jié)構(gòu)體:
public struct Thermometer {
public var temperature: Double
public init(temperature: Double) {
self.temperature = temperature
}
}
可以使用以下代碼創(chuàng)建實(shí)例:
var t: Thermometer = Thermometer(temperature:56.8)
但以這種方式初始化它會(huì)更好:
var thermometer: Thermometer = 56.8
你可以嗎? 要怎么做?
Swift定義了一些協(xié)議,使你可以使用賦值運(yùn)算符初始化具有文字值的類(lèi)型萄唇。
采用相應(yīng)的協(xié)議并提供公共初始化器允許特定類(lèi)型的文字初始化檩帐。在 Thermometer 的情況下,實(shí)現(xiàn)ExpressibleByFloatLiteral如下:
extension Thermometer: ExpressibleByFloatLiteral {
public init(floatLiteral value: FloatLiteralType) {
self.init(temperature: value)
}
}
現(xiàn)在另萤,可以使用float創(chuàng)建實(shí)例湃密。
var thermometer: Thermometer = 56.8