做者本身說本身很喜歡swift,由於他喜歡Haskell。可能看上了swift支持函數式編程的緣故。編程
中間扯皮各類略。。。swift
扯到函數編程剛開始不習慣可是會帶來方便。。略結束。。。數組
ex by oc:安全
- (NSAttributedString *)attributedString:(NSString *)input { return [[NSAttributedString alloc] initWithString:input]; }
看上去無公害,可是參數若是是nil,那邊會致使崩潰。並且更坑爹是在運行時纔會發現這個問題。這種問題一旦是你的下游程序猿(用戶)去接手的時候,找這個BUG就不是很好找了咯。數據結構
對比Swift寫法:多線程
extension NSAttributedString { init(string str: String) }
若是能夠傳入一個nil值得參數,那麼接口會變成這樣:框架
extension NSAttributedString { init(string str: String?) }
這種寫法的優點在於更強的解釋性,也省去了看文檔的時間。更不會致使運行時錯誤。函數式編程
儘可能避免無用選項關鍵字。用選項關鍵字是確實須要才使用的,好比你的參數是顏色,顏色須要符合某種要求。若是此時你的參數不知足這種要求那麼你但願返回nil:函數
func parseColorFromHexString(input: String) -> UIColor? { // ... }
枚舉是swift得新特性,與OC的枚舉有顯著的不一樣。OC中的枚舉說白了就是整型。線程
讓咱們考慮下布爾類型。咱們只須要考慮真或假。
在選項關鍵字也是這樣的原理,也只有兩種狀況:有值跟nil.swift中選項與布爾一樣都用枚舉定義。不一樣的是選項枚舉是帶綁定值得。咱們來看下各自的定義:
enum Boolean { case False case True } enum Optional<A> { case Nil case Some(A) }
二選一枚舉常常在函數式編程中用於你在兩件事物中進行選擇的場景。舉個栗子,若是你想返回一個整型或者錯誤,你可使用Either<Int, NSError>
。若是你要存一個布爾或者字符串的字典,你可使用Either<Bool, String>做爲Key值。
清楚的知道何時該用枚舉何時不應用枚舉有一點難度,當咱們爲一組相近類型得數據建立結構的時候。栗子,若是咱們用swift來封裝Github的接口,咱們須要把各類暴露出的接口用枚舉型來表示。爲了得到用戶頭像,咱們提供用戶名。獲取用戶版本庫咱們提供了用戶名跟,排序布爾值。
enum Github { case Zen case UserProfile(String) case Repositories(username: String, sortAscending: Bool) }
定義開發性接口使用枚舉真是棒極了。接口列表是受限的,咱們能夠定義各種接口。若是遺漏了某個枚舉值咱們會接受到一個告警。若是咱們擅自添加了一類狀況,咱們須要更新全部用到該類枚舉類型得代碼。
其餘使用枚舉的時候不能隨意添加case,除非有代碼權限。這是一個很是好的限制。假想下你能夠添加一個情形到Bool或者Optional,那麼你全部用來它得方程都得重寫。
讓咱們拿貨幣轉換器作個栗子:
enum Currency { case Eur case Usd }
這樣咱們能夠根據貨幣字符串來獲取貨幣符號:
func symbol(input: Currency) -> String { switch input { case .Eur: return "€" case .Usd: return "$" } } func format(amount: Double, currency: Currency) -> String { let formatter = NSNumberFormatter() formatter.numberStyle = .CurrencyStyle formatter.currencySymbol = symbol(currency) return formatter.stringFromNumber(amount) }
在swift不能簡單去繼承父類來擴展枚舉類型。須要經過用協議來實現枚舉的擴展。
protocol CurrencySymbol { func symbol() -> String }
如今,咱們可讓Currency
成爲協議的一個實例,如今咱們能夠將input參數剔除,由於默認傳入self
:
extension Currency : CurrencySymbol { func symbol() -> String { switch self { case .Eur: return "€" case .Usd: return "$" } } }
重寫format
:
func format(amount: Double, currency: CurrencySymbol) -> String { let formatter = NSNumberFormatter() formatter.numberStyle = .CurrencyStyle formatter.currencySymbol = currency.symbol() return formatter.stringFromNumber(amount) }
如今咱們能夠經過讓各類各樣的數據類型來遵循這個協議的方式讓咱們的代碼具備靈活的擴展性,好比如今有比特幣類型:
struct Bitcoin : CurrencySymbol { func symbol() -> String { return "B⃦" } }
如今經過協議而並不是具體類的方式來應對各類數據類型參數值得方式可使咱們的代碼更易於擴展。你可使用便利的擴展搭配使用協議,你的代碼將更具語言表達力!請根據你的實際狀況決定你的忌口是開放仍是封閉!
swift還有一個優點在於它的類型(數據)安全,正如前面說到的optionals
。咱們能夠將類型檢查從運行時提到編譯時經過一些技巧。舉個數組的栗子,數組是泛型的,它能夠容納同一類型的元素。不能夠在字符串數組內添加整型。(固然你能夠經過Either
來弄出一個混合數組。。 - -||)
又假設咱們要將currency converter
變成一個通用的轉換器。若是咱們用Double
來表示總數,這樣會致使必定的混淆。舉個栗子,100.0可能意味着100美圓,100千克,或者其餘表明100的東東。咱們要作的是讓類型系統來爲咱們根據物理量建立出相對應得數據類型。舉個栗子,咱們能夠定義這樣的一個類型來描述貨幣:
struct Money { let amount : Double let currency: Currency }
一樣,咱們能夠定義質量的數據結構:
struct Mass { let kilograms: Double }
這樣能夠增長代碼的可讀性,假設咱們有以下重量方程的接口:
func pounds(input: Double) -> Double
這樣顯然太晦澀了,咱們能夠這麼寫:
func pounds(input: Mass) -> Double
這樣寫的好處有二,其一是代碼解釋性強了,第二編譯器會幫咱們進行類型檢查。
另外一個swift支持的特性是內置支持值不可變。在Cocoa框架裏面有不少API的參數設置爲不可變額。還有成雙出現得一些類表達可變不可變(NSString vs. NSMutableString, NSArray vs. NSMutableArray)。在swift中就簡單明瞭多了:
var修飾的變量可變而let修飾的變量不可變。好處是接口更具備表達性以及涉及多線程操做更爲容易。
令做者倍感欣慰的是編譯器作了原來咱們讀文檔須要的活兒。而後也預測了下將來。。。略。。