swift 基礎(chǔ)知識(shí)積累

一些優(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。
思維導(dǎo)圖
#一莲镣、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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市四敞,隨后出現(xiàn)的幾起案子泛源,更是在濱河造成了極大的恐慌,老刑警劉巖忿危,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件达箍,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡铺厨,警方通過(guò)查閱死者的電腦和手機(jī)幻梯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)努释,“玉大人碘梢,你說(shuō)我怎么就攤上這事》サ伲” “怎么了煞躬?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)逸邦。 經(jīng)常有香客問(wèn)我恩沛,道長(zhǎng),這世上最難降的妖魔是什么缕减? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任雷客,我火速辦了婚禮,結(jié)果婚禮上桥狡,老公的妹妹穿的比我還像新娘搅裙。我一直安慰自己,他們只是感情好裹芝,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布部逮。 她就那樣靜靜地躺著,像睡著了一般嫂易。 火紅的嫁衣襯著肌膚如雪兄朋。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天怜械,我揣著相機(jī)與錄音颅和,去河邊找鬼傅事。 笑死,一個(gè)胖子當(dāng)著我的面吹牛峡扩,可吹牛的內(nèi)容都是我干的蹭越。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼有额,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼般又!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起巍佑,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤茴迁,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后萤衰,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體堕义,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年脆栋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了倦卖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡椿争,死狀恐怖怕膛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情秦踪,我是刑警寧澤褐捻,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站椅邓,受9級(jí)特大地震影響柠逞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜景馁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一板壮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧合住,春花似錦绰精、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至获洲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間殿如,已是汗流浹背贡珊。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工最爬, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人门岔。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓爱致,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親寒随。 傳聞我的和親對(duì)象是個(gè)殘疾皇子糠悯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容