前言
雖然編程語言不會那么容易消逝,但堅持衰落范例的開發(fā)小組正在這么做。如果你正為移動設(shè)備開發(fā)應(yīng)用程序,并且你還沒有研究Swift,那么注意:當(dāng)Swift涉及到Mac、iPhone、ipad、Apple Watch和未來設(shè)備的應(yīng)用開發(fā)時,它不僅會排擠掉Objective-C,而且還會取代在Apple平臺中做嵌入式開發(fā)的C語言。 Swift有大量有趣的語法、特性、特點,只要掌握了用法就可以利用好它們。
在這篇文章中我會帶你瀏覽我選擇出的10條小提示,并附有已驗證的代碼供大家試用。
1.類與協(xié)議的existential
Existential類型允許我們說出想要一個類型具有哪種功能,而不用請求某些特定的東西。比如我們可以寫一個接收類或子類的函數(shù):
func process(user: User) { }
之后我們寫一個函數(shù),讓它能接收符合某個協(xié)議的任意類型對象:
func identify(thing: Identifiable) { }
Swift允許我們讓existential同時代表類與協(xié)議
下例中,有一個協(xié)議和一個符合該協(xié)議的類
protocol CanCook { }class CelebrityChef: CanCook { }
之后再有一個類,并附有一個子類
class Appliance { }class Hairdryer: Appliance { }
現(xiàn)在我們有了一個定義東西是否CanCook的協(xié)議,和一個定義我們家里東西的類。當(dāng)我們把這兩個合二為一時候就變得復(fù)雜了——用餐飲工具(Appliance)做飯。
定義它們很簡單,因為它們可以歸入Appliance的子類,并符合CanCook
class Oven: Appliance, CanCook { }class Microwave: Appliance, CanCook { }
Swift的existential可以支持使用它們。但除非你是認識某個大廚,不然你應(yīng)該找不到一個大廚來你家做飯。類似的,除非你實在沒辦法,你也不會用一個吹風(fēng)機做飯。
結(jié)果就是,這兩個函數(shù)都不夠好用——它們并沒有完整描繪出我們想要接收的文件類型:
func makeDinner(using: Appliance) { }func makeDinner(using: CanCook) { }
好在通過寫Appliance & CanCook,Swift讓我們能夠把協(xié)議與子類合并到一個existential中。我們希望某些東西是日常工具(Appliance),并符合CanCook協(xié)議,就像這樣:
func makeDinner(using: Appliance & CanCook) { }
2.協(xié)議擴展可以提供默認屬性值
協(xié)議擴展為方法的執(zhí)行提供了默認屬性值,這些默認值之后可以被符合類型覆蓋,但你也可以用它們?yōu)閷傩蕴峁┠J值。
下例中我們創(chuàng)建一個Fadeable協(xié)議,并在設(shè)定好的秒數(shù)后逐漸淡出:
protocol Fadeable { var fadeSpeed: TimeInterval { get } func fadeOut()}
比起給所有符合類型添加各自的淡出速度和fadeOut()方法,我們可以在一個協(xié)議擴展中為它們提供默認值。
extension Fadeable where Self: UIView { var fadeSpeed: TimeInterval { return 1.0 } func fadeOut() { UIView.animate(withDuration: fadeSpeed) { self.alpha = 0 } }}
這樣你可以讓新的子類符合它們,而不用擔(dān)心重復(fù)寫相同的默認值
class MyViewClass: UIView, Fadeable { }
3.檢查所有的集合項目是否滿足一個狀態(tài)
Swift 4.2新推出了allSatisfy()方法,讓它運行一個狀態(tài)閉包(condition closure),如果傳遞給這個閉包后,所有元素都返回true,那么allSatisfy()就返回true
例如某人考試結(jié)果數(shù)組如下:
let scores = [85, 88, 95, 92]
根據(jù)一個學(xué)生是否所有考試都達到85分,決定他是否通過。
let passed = scores.allSatisfy { $0 >= 85 }
4.使用解構(gòu)(destructuring)操作元祖(tuples)
解構(gòu)能夠把元祖分解成獨立數(shù)值,這樣就可以更容易的操作它們。比如你也許想調(diào)用這樣一個函數(shù):
func getCredentials() -> (name: String, password: String) { return ("Taylor Swift", "biebersux")}
它會返回一個包含兩個字符串的元祖,如果你想讓他們繼續(xù)在一起,你可以:
let user = getCredentials()print(user.name)print(user.password)
然而,重構(gòu)讓我們能夠把它們分開:
let (username, password) = getCredentials()print(username)print(password)
你甚至可以在函數(shù)被調(diào)用完后做這些——它們是一樣的:
let user = getCredentials()let (username, password) = user
這個技術(shù)讓Swift能夠簡單輕易地解決一個經(jīng)典入門代碼問題:怎樣在不使用第三個變量的情況下,交換兩個變量。
多虧重構(gòu),Swift才能有這種最簡單的解決方式:
var a = 10var b = 20(a, b) = (b, a)
5.通過溢出(overflow)算符讓加減法能夠環(huán)繞處理
所有的Swift整型都有最大值,比如UInt8的最大值是255,Int64的最大值是9,223,372,036,854,775,807。
為了保證安全,如果超過整型的限值,Swift會自動崩潰。比如下面的代碼在編譯時沒問題而運行時會崩潰
let highScore = Int8.maxlet newHighScore = highScore + 1
因為它在Int8.max上加1,產(chǎn)生了超過Int8存儲范圍的128。盡管崩潰聽起來不好,但是至少它保證了安全。
不過,Swift提供了另一種處理方法:我們可以用overflow做加法,它讓Swift繞回最小值,而不是崩潰。
let highNumber = UInt8.maxlet nextNumber = highNumber &+ 1
它實際上挺常用,例如MySQL數(shù)據(jù)庫會自動分配整數(shù)ID到數(shù)據(jù)庫表單的行中。但是當(dāng)整數(shù)都用完后,它會繞回并從1開始查到未使用ID,其中有些會隨時間被刪除。
6.公眾只讀,個人可寫
盡管Swift的訪問控制過去倍受詬病,但通過使用2個不同的訪問控制屬性可以改善很多。
例如下面的結(jié)構(gòu)代表一家銀行:
struct Bank { var address: String}
我們對address沒有使用任何訪問控制,意味著任何人都可以讀取并改寫它。如果我們對這個屬性用private,別人是改不了它,但也無法讀它了。
Swift做出了一個兼顧:public private(set)
它可以讓一個屬性可被讀取,但不能被寫入。這樣所有人都可以讀取我們銀行的地址,但只有銀行才能改它。
struct Bank { public private(set) var address: String}
7.成員逐一初始化(memberwise initializers)與自定初始化協(xié)同
Swift結(jié)構(gòu)默認用成員逐一初始化,它可以方便快捷地創(chuàng)建實例
struct Score { var player: String var score: Int} let highScore = Score(player: "twostraws", score: 556)
但是如果你創(chuàng)建自己的初始化,你會自動失去成員逐一初始化。這是考慮到安全問題:你的初始化似乎是做了一些你覺得很重要的額外工作,所以如果Swift還用成員逐一初始化,那你的額外工作會被跳過。
如果你想要你的初始化與成員逐一初始化同時使用,步驟很簡單。把你的初始化聲明到一個擴展中,像這樣:
struct Score { var player: String var score: Int} extension Score { init(player: String) { self.player = player score = 0 }} // 現(xiàn)在它們都可用了let highScore1 = Score(player: "twostraws", score: 0)let highScore2 = Score(player: "twostraws")
8.static vs class屬性
Swift中的類屬性可以用2種關(guān)鍵詞創(chuàng)建:static 和 class。它們都能讓一個類中所有實例共享某個屬性,但static意味著final,即無法在子類中被覆蓋。
例如我們可以創(chuàng)建一個Building類,并定義一個用于存儲建筑規(guī)劃的class屬性,和一個用于存儲安全須知的static屬性。
class Building { class var zoningRestrictions: String { return "None" } static var safetyRequirements: [String] { return ["Fire escapes", "Sprinklers"] }}
因為zoningRestrictions是class屬性,可以在子類中修改,比如居民區(qū)建住房,商業(yè)區(qū)建寫字樓等等。相對的safetyRequirements是一個static屬性,意味著所有房屋和子類必須符合安全法規(guī)。
代碼如下:
class Skyscraper: Building { // this is allowed override class var zoningRestrictions: String { return "Dense commercial only" } // but this is not override static var safetyRequirements: [String] { return ["Sprinklers"] }}
9. == 和 === 是不一樣的
==運算符用于檢測兩個Equatable類型是否相等,例如
1 == 1"kayak" == String("kayak".reversed())[2, 4, 6] == [1, 2, 3].map { $0 * 2 }
通過對Equatable的自動綜合分析,對==的支持就像對類型定義添加Equatable一樣簡單。但如果是對類,有另一個運算符:===。
因為類中的實例只不過是對內(nèi)存特定地址的引用,===用于檢查一個類中的2個實例是否指向同一段內(nèi)存地址。
所以下面的情況會被認為是true
class Lightsaber { var color = "Blue"} let saber1 = Lightsaber()let saber2 = saber1saber1 === saber2
===運算符完全不使用Equatable,這就是說如果你創(chuàng)建2個擁有相同屬性的獨立對象,===會返回false
let saber3 = Lightsaber()saber1 === saber3
10.通過numericCast()在整型間轉(zhuǎn)換
在使用整數(shù)方面,Swift一直有高度選擇性,如果你不留意,經(jīng)常會發(fā)現(xiàn)你的代碼中分散著Int(), UInt32(),和其他類型轉(zhuǎn)換。也許這段代碼不會出錯,但它并不易于閱讀:這就是為什么我們需要強制制定一種整型。
Swift有個專用的整型轉(zhuǎn)換函數(shù)numericCast() 用了它就可以做到“我不關(guān)心這里需要什么類型,請查明白”。這樣比起硬編碼的類型,它可以更清楚的傳達你的意圖:為了運行的更好,你需要把一種整型轉(zhuǎn)換到另外一種,但并不關(guān)心到底是怎么轉(zhuǎn)換的
它的常用地點之一是arc4random_uniform()函數(shù),這個函數(shù)會接收一個UInt32參數(shù)并返回一個UInt32,這里經(jīng)常要在Int與UInt32之間加類型轉(zhuǎn)換。
使用numericCast的話,你就可以寫出很好的任意范圍的實現(xiàn)
func random(in range: Range<int>) -> Int { return numericCast(arc4random_uniform(numericCast(range.count))) + range.lowerBound}</int>
額外小技巧:如果不用 ! 那用什么
不是所有人都喜歡NOT運算符,!,主要是因為它讀起來不自然。然而Swift中功能,方法,閉包,運算符之間的界限變得模糊了。所以如果你想的話,可以把!轉(zhuǎn)化為它的函數(shù):
let not = (!)
現(xiàn)在你可以用not(someBool)代替!someBool
let loggedIn = false if not(loggedIn) { print("Please log in.")}
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網(wǎng)的支持。
新聞熱點
疑難解答
圖片精選