Swift 語言面面觀(一)

Swift 語言面面觀(一)

在 WWDC 2014(蘋果 2014 年開發者大會)發佈的 Swift 編程語言,大約在一週內將迎來它的兩週歲生日(譯註:WWDC 2014 的時間是 2014-6-3)。當時聽到這個消息,咱們在工做室裏興奮地跳了起來,並今後投入到了 Swift 的懷抱。然而兩年時間過去了,我依然在苦苦思索着怎樣寫出好的 Swift 代碼。要知道 Objective-C 已經快有三十年曆史了,咱們都已經摸索出 Objective-C 的最佳實踐,以及什麼是好或壞的 Objective-C 代碼,然而 Swift 還很年輕。dom

在這一系列的文章裏,我將嘗試提煉出我認爲的 Swift 語言中好與很差的部分。誠然我不是這方面的專家,我只是但願拋磚引玉,分享我對這個問題的思考,並激勵其它開發者(沒錯就是你)表達本身的看法。若是你對此有任何想法、批評,或者對於好代碼的見解,能夠在原文下面留言,或者 在 Twitter 上聯繫我編程語言

讓咱們進入正題。ide

使用枚舉類型(Enums)避免代碼中的字符串輸入錯誤

我早已沒法數清我有多少次犯下了同一種錯誤:花費大量時間在尋找字符串拼寫錯誤致使的各類各樣的古怪 bug。枚舉類型除了能夠幫你節省調試時間外,還能夠減小字符輸入的時間,由於 XCode 的代碼補全功能會推薦定義好的枚舉值。函數

在使用 NSURLSession 的每一個項目裏,我都包含了下面的代碼片斷:字體

enum HTTPMethod: String {
    case GET = "GET"
    case POST = "POST"
    case PUT = "PUT"
    case DELETE = "DELETE
}

這是一個很是簡單的枚舉,我知道大部分的開發者可能都不屑於這麼作。然而基於上述緣由,我確實是這麼使用的。

更新: Tobias Due Munk 指出,你甚至不須要把和鍵名相同的值字符串寫出來,Swift 有更簡化的語法。你只須要這樣寫:

enum HTTPMethod: String { case GET, POST, PUT, DELETE }

使用訪問控制關鍵詞限制內容可訪問性

稍等一下子,還記得 public, private, internal 這都是什麼鬼嗎?爲何會有一種 Java 既視感?就跟大部分 CS(計算機科學)專業畢業生同樣,我也寫過 Java 代碼,但是我不喜歡這門語言及其生態系統。然而,儘管我不喜歡它,但不得不認可這門語言有着一些明智的設計。若是你正在爲其餘開發者提供 API,而他們不清楚代碼的輸入輸出,此時你就會明白定義完善且文檔清晰的 API 的重要性了。所以,合理地添加權限控制關鍵詞到 API 方法中,能夠幫助你的用戶更好地理解你的 API 「表面積」,並尋找到他們想要調用的接口。固然,你也能夠寫文檔來解釋應該使用哪些方法,哪些應該保留下來,可是爲何不經過添加關鍵詞來強制實行呢?

讓我感到吃驚的是,我曾經和很多開發者聊過,他們並不喜歡添加權限控制關鍵詞。其實對於 iOS/OS X 開發者而言,權限控制的概念並不新鮮。在 Objective-C 中,咱們就把「公有的」接口放在 .h 文件中,而把「私有的」接口放在 .m 文件中。

在寫 Swift 代碼的過程當中,我老是遵循「最嚴格的」原則,在一開始儘量先把全部類、結構、枚舉以及函數設成私有。若是以後我發現須要一個函數暴露在類外,我纔會嘗試下降這個限制。經過遵循這一原則,我能夠實現最小化 API 「表面積」,方便其餘開發者調用。

使用泛型避免 UIKit 模板代碼

自從 Swift 出現之後,我就一直在代碼邏輯中徹底實現 view 和 view controller。做爲曾經的 Storyboard 重度用戶的我,如今發現把全部的屬於視圖的代碼放在一個地方,比起分開放在 XML 文件和幾行邏輯代碼更加實用。

在編寫了大量 view 和 view controller 代碼以後,我遇到了一個難題。由於我更喜歡 auto layout,因此我偏向於不使用參數初始化視圖(init:frame 是指定構造器)。若是你在 Swift 中,對於任何的 UIKit 類指定一個無參數的構造函數,你就不得不指定一個 init:coder 構造器。這很煩人,爲了不每次建立視圖都寫這段模板代碼,我建立了一個 「泛型視圖類(Generic View Class)」 ,讓全部視圖繼承這個類而無需繼承 UIView。

public class GenericView: UIView {
    public required init() {
        super.init(frame: CGRect.zero)
        configureView()
    }
    public required init?(coder: NSCoder) {
        super.init(coder: coder)
        configureView()
    }
    internal func configureView() {}
}

這個類同時也表達出個人另外一個編程習慣:建立一個 「configureView」 方法,把全部配置視圖的操做,包括添加子視圖、約束、調整顏色、字體等,全都放到這個方法中。這樣的話,不管何時建立視圖,我都不須要再寫一遍上述的模板代碼了。

class AwesomeView: GenericView {
    override func configureView() {
        ....
    }
}
let awesomeView = AwesomeView()

當你把這個模式配合泛型 view controller 一塊兒使用,效果更佳。

public class GenericViewController<View: GenericView>: UIViewController {
    internal var contentView: View {
        return view as! View
    }
    public init() {
        super.init(nibName: nil, bundle: nil)
    }
    public required init?(coder: NSCoder)
        super.init(coder: coder)
    }
    public override func loadView() {
        view = View()
    }
}

如今要給視圖建立 view controller 更加簡單了。

class AwesomeViewController: GenericViewController<AwesomeView> {
    override func viewDidLoad()
        super.viewDidLoad()
        ....
    }
}

我把這個模式的代碼抽離出來,放到了一個 GitHub repo 中。這套代碼能夠配合 Carthage 或者 CocoaPods 做爲一套框架使用。

我贊成這 4 個基類幾乎沒實現什麼功能,也稱不上一套框架。之因此發佈這套代碼,是由於我以爲對於大部分人來講,這種用法是最容易上手的方式。我以爲你徹底能夠把這幾個類複製粘貼到你的代碼當中,我預計不會對這套代碼做出很大修改了。

以上就是 Swift 語言面面觀系列的第一部分,期待你們更多的想法、批評和建議。歡迎在下面留言,或者 給我發 Twitter

相關文章
相關標籤/搜索