Swift 已經出了5個年頭了,到如今,它的語法已經很穩定,iOS developers 能夠放心使用了。我從1.0版本就開始使用 Swift,儘管也穿插了一些 Objective-C 項目,但整體來講還算用得熟手。目前團隊已經全面普及了 Swift,基本不會去寫 Objective-C 了。本文寫給還在用 Objective-C 的同行,但願大家認真考慮一下 Swift。程序員
一開始接觸 Swift 的人可能會對 ?
和 !
的操做很疑惑,甚至是渾身不自在。使用一段時間以後,就真香了。這個特性的用處是讓編譯器在編譯時就把nil
異常檢測出來,讓開發者提早處理,從而不會把有這種問題的代碼發到線上去。swift
Swift 的編譯檢測很是強大,這也是一門純編譯語言的優點。我也兼職寫過一些 ruby 的後臺,對 ruby 的運行時空異常深惡痛絕。ruby
NoMethodError (undefined method `hello' for nil:NilClass)
複製代碼
你永遠都不想在線上出問題,這就是 Optional 特性的意義。bash
打個比方,我簡單地想使用一個url,這個url string是傳過來的。閉包
let someURLString = "https://Çhello world"
guard let url = URL(string: someURLString) else {
fatalError("url went wrong \(someURLString)")
}
//..do something with url
print(url)
複製代碼
當個人url字符串含有非法字符的時候,我會獲得一個nil
,並可能在後續下面的代碼拋出錯誤,致使crash。app
若是幸運的話,直接在當前的代碼塊就拋錯了,那還好修復。若是這個nil
通過了不少層,那就糟糕了。網站
做爲一門全新的語言,Swift 站在巨人的肩膀上,把枚舉這種語言特性設計得簡直完美。 好比,你的枚舉類型能夠是字符串的。ui
enum Gender: String {
case male
case female
}
print(Gender.male.rawValue)
複製代碼
這樣的話,避免一堆未定義的字符串橫行。url
它還能夠在內部定義方法,或者返回一個值,還能夠遍歷。舉一個例子:spa
class ViewController: UIViewController {
let tableView = UITableView()
init() {
CellType.allCases.forEach { (cellType) in
cellType.register(to: tableView)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension ViewController {
enum CellType: String, CaseIterable {
case business1
case business2
var cellId: String {
return self.rawValue
}
func register(to tableView: UITableView) {
switch self {
case .business1: tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
case .business2: tableView.register(UINib(nibName: "SomeCell", bundle: nil), forCellReuseIdentifier: cellId)
}
}
}
}
複製代碼
當理解了業務是一種互斥關係的時候,用枚舉把這些列舉出來,並在內部處理以後,返回一個值,減小大量的if else
,這樣組織的話,代碼就舒服了。
Objective-C 的 block 在實用方面已經作得很好,Swift 的閉包在此基礎上再進一步。能夠直接在裏面聲明所捕獲的變量(好比self),衆周所知,閉包/block這種代碼組織方式可讓代碼更加緊湊,同時有捕獲局部變量的好處。可是當一個方法寫了一大塊,裏面含有一個閉包/block,不知道捕獲了什麼致使引用循環,這是難以調試的錯誤,所以在閉包內聲明所捕獲的變量是大有裨益的。
一般來講,這個用在 weak self 來弱引用 self 就能完成大部分的事情。
login(phone: "xxx", password: "pswd") { [weak self] (success) in
self?.tableView.reloadData()
}
複製代碼
因爲 Swift 有空的檢測,因此只用 weak self 不會有問題,好比你在閉包執行這樣的代碼是不行的,直接報編譯錯誤:
var titles = [String]()
titles.append(self?.title)
複製代碼
可是 Objective-C 的block可能會有存在的問題
[titles addObject: weakSelf.title];
複製代碼
還有一點,或許是最重要的,就是咱們終於擺脫了 Objective-C 奇怪的 block 語法了!!這裏有一篇總結得很好(注意網站名) fuckingblocksyntax.com
最近看了一部紀錄片,叫《單挑荒野》,長期混B站的人可能熟悉,裏面的主人翁艾德一個主旨就是,不但要生存下去,並且要活得滋潤。程序員也同樣,不但要實現功能,還得優雅地實現,寫出讓本身感到滿意,舒服的代碼。
實現一樣的邏輯,Swift 可能不會比 Objective-C 少多少代碼,但必定好看,舒服。
好比,你不須要聲明這個變量的類型,由於在初始化的時候就已經知道。
let tableView = UITableView()
複製代碼
vs
UITableView *tableView = [[UITableView alloc] init];
複製代碼
好比枚舉,你會常常看到 Objective-C 這樣的代碼:
typedef NS_ENUM(NSInteger, UIModalTransitionStyle) {
UIModalTransitionStyleCoverVertical = 0,
UIModalTransitionStyleFlipHorizontal __TVOS_PROHIBITED,
UIModalTransitionStyleCrossDissolve,
UIModalTransitionStylePartialCurl NS_ENUM_AVAILABLE_IOS(3_2) __TVOS_PROHIBITED,
}
複製代碼
而 Swift 就舒服多了
enum UIModalTransitionStyle : Int {
case coverVertical
case flipHorizontal
case crossDissolve
case partialCurl
}
複製代碼
我不太喜歡用NSAttributedString,由於感受老是把代碼寫得亂糟糟,但在 Swift 則舒服得多。
let attributedString = NSAttributedString(
string: "Hello world",
attributes: [
.font: UIFont.systemFont(ofSize: 14),
.foregroundColor: UIColor.blue
]
)
複製代碼
還能夠稍微擴展一下 Int 類型,能夠寫出更簡潔明瞭的語句
extension Int {
var font: UIFont {
return UIFont.systemFont(ofSize: CGFloat(self))
}
var lineHeight: NSMutableParagraphStyle {
let para = NSMutableParagraphStyle()
para.maximumLineHeight = CGFloat(self)
para.minimumLineHeight = CGFloat(self)
return para
}
}
let attributedString = NSAttributedString(
string: "Hello world",
attributes: [
.font: 14.font,
.paragraphStyle: 20.lineHeight,
.foregroundColor: UIColor.blue
]
)
複製代碼
差很少就想到這些,權當盤磚引玉,短短篇幅也沒辦法覆蓋全部的 Swift 優勢。