當前位置:
首頁 > 最新 > 10條Swift小提示

10條Swift小提示

Swift有大量有趣的語法、特性、特點,只要掌握了用法就可以利用好它們。在這篇文章中我會帶你瀏覽我選擇出的10條小提示,並附有已驗證的代碼供大家試用。

1.類與協議的existential

Existential類型允許我們說出想要一個類型具有哪種功能,而不用請求某些特定的東西。比如我們可以寫一個接收類或子類的函數:

之後我們寫一個函數,讓它能接收符合某個協議的任意類型對象:

Swift允許我們讓existential同時代表類與協議

下例中,有一個協議和一個符合該協議的類

之後再有一個類,並附有一個子類

現在我們有了一個定義東西是否CanCook的協議,和一個定義我們家裡東西的類。當我們把這兩個合二為一時候就變得複雜了——用餐飲工具(Appliance)做飯。

定義它們很簡單,因為它們可以歸入Appliance的子類,並符合CanCook

Swift的existential可以支持使用它們。但除非你是認識某個大廚,不然你應該找不到一個大廚來你家做飯。類似的,除非你實在沒辦法,你也不會用一個吹風機做飯。

結果就是,這兩個函數都不夠好用——它們並沒有完整描繪出我們想要接收的文件類型:

好在通過寫Appliance & CanCook,Swift讓我們能夠把協議與子類合併到一個existential中。我們希望某些東西是日常工具(Appliance),並符合CanCook協議,就像這樣:

2.協議擴展可以提供默認屬性值

協議擴展為方法的執行提供了默認屬性值,這些默認值之後可以被符合類型覆蓋,但你也可以用它們為屬性提供默認值。

下例中我們創建一個Fadeable協議,並在設定好的秒數後逐漸淡出:

比起給所有符合類型添加各自的淡出速度和fadeOut()方法,我們可以在一個協議擴展中為它們提供默認值。

這樣你可以讓新的子類符合它們,而不用擔心重複寫相同的默認值

3.檢查所有的集合項目是否滿足一個狀態

Swift 4.2新推出了allSatisfy()方法,讓它運行一個狀態閉包(condition closure),如果傳遞給這個閉包後,所有元素都返回true,那麼allSatisfy()就返回true

例如某人考試結果數組如下:

根據一個學生是否所有考試都達到85分,決定他是否通過。

4.使用解構(destructuring)操作元祖(tuples)

解構能夠把元祖分解成獨立數值,這樣就可以更容易的操作它們。比如你也許想調用這樣一個函數:

它會返回一個包含兩個字元串的元祖,如果你想讓他們繼續在一起,你可以:

然而,重構讓我們能夠把它們分開:

你甚至可以在函數被調用完後做這些——它們是一樣的:

這個技術讓Swift能夠簡單輕易地解決一個經典入門代碼問題:怎樣在不使用第三個變數的情況下,交換兩個變數。

多虧重構,Swift才能有這種最簡單的解決方式:

5.通過溢出(overflow)算符讓加減法能夠環繞處理

所有的Swift整型都有最大值,比如UInt8的最大值是255,Int64的最大值是9,223,372,036,854,775,807。

為了保證安全,如果超過整型的限值,Swift會自動崩潰。比如下面的代碼在編譯時沒問題而運行時會崩潰

因為它在Int8.max上加1,產生了超過Int8存儲範圍的128。儘管崩潰聽起來不好,但是至少它保證了安全。

不過,Swift提供了另一種處理方法:我們可以用overflow做加法,它讓Swift繞回最小值,而不是崩潰。

它實際上挺常用,例如MySQL資料庫會自動分配整數ID到資料庫表單的行中。但是當整數都用完後,它會繞回並從1開始查到未使用ID,其中有些會隨時間被刪除。

6.公眾只讀,個人可寫

儘管Swift的訪問控制過去倍受詬病,但通過使用2個不同的訪問控制屬性可以改善很多。

例如下面的結構代表一家銀行:

我們對address沒有使用任何訪問控制,意味著任何人都可以讀取並改寫它。如果我們對這個屬性用private,別人是改不了它,但也無法讀它了。

Swift做出了一個兼顧:public private(set)。它可以讓一個屬性可被讀取,但不能被寫入。這樣所有人都可以讀取我們銀行的地址,但只有銀行才能改它。

7. 成員逐一初始化(memberwise initializers)與自定初始化協同

Swift結構默認用成員逐一初始化,它可以方便快捷地創建實例

但是如果你創建自己的初始化,你會自動失去成員逐一初始化。這是考慮到安全問題:你的初始化似乎是做了一些你覺得很重要的額外工作,所以如果Swift還用成員逐一初始化,那你的額外工作會被跳過。

如果你想要你的初始化與成員逐一初始化同時使用,步驟很簡單。把你的初始化聲明到一個擴展中,像這樣:

8. static vs class屬性

Swift中的類屬性可以用2種關鍵詞創建:static 和 class。它們都能讓一個類中所有實例共享某個屬性,但static意味著final,即無法在子類中被覆蓋。

例如我們可以創建一個Building類,並定義一個用於存儲建築規劃的class屬性,和一個用於存儲安全須知的static屬性。

因為zoningRestrictions是class屬性,可以在子類中修改,比如居民區建住房,商業區建寫字樓等等。相對的safetyRequirements是一個static屬性,意味著所有房屋和子類必須符合安全法規。代碼如下:

9. == 和 === 的不同

==運算符用於檢測兩個Equatable類型是否相等,例如

通過對Equatable的自動綜合分析,對==的支持就像對類型定義添加Equatable一樣簡單。但如果是對類,有另一個運算符:===。

因為類中的實例只不過是對內存特定地址的引用,===用於檢查一個類中的2個實例是否指向同一段內存地址。所以下面的情況會被認為是true

===運算符完全不使用Equatable,這就是說如果你創建2個擁有相同屬性的獨立對象,===會返回false

10.通過numericCast()在整型間轉換

在使用整數方面,Swift一直有高度選擇性,如果你不留意,經常會發現你的代碼中分散著Int(), UInt32(),和其他類型轉換。也許這段代碼不會出錯,但它並不易於閱讀:這就是為什麼我們需要強制制定一種整型。

Swift有個專用的整型轉換函數numericCast(),用了它就可以做到「我不關心這裡需要什麼類型,請查明白」。這樣比起硬編碼的類型,它可以更清楚的傳達你的意圖:為了運行的更好,你需要把一種整型轉換到另外一種,但並不關心到底是怎麼轉換的

它的常用地點之一是arc4random_uniform()函數,這個函數會接收一個UInt32參數並返回一個UInt32,這裡經常要在Int與UInt32之間加類型轉換。

使用numericCast的話,你就可以寫出很好的任意範圍的實現

額外小技巧:如果不用 ! 那用什麼

不是所有人都喜歡NOT運算符,!,主要是以為它讀起來不自然。然而Swift中功能,方法,閉包,運算符之間的界限變得模糊了。所以如果你想的話,可以把!轉化為它的函數:

現在你可以用not(someBool)代替!someBool


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Cocoa開發者社區 的精彩文章:

Xcode10新內容

TAG:Cocoa開發者社區 |