SnapKit 原始碼解讀(一):Extensions

小橘爺發表於2018-05-14

前言

iOS 開發中的佈局方式,總體而言經過了三個時代。混沌初開之時,世間只有3.5英寸(iPhone 4、iPhone 4S),那個時候螢幕適配對於大多數 iOS 開發者來說並不是什麼難題,用 frame 就能精確高效的定位。這之後,蘋果釋出了4英寸機型(iPhone 5、iPhone 5C、iPhone 5S),與此同時蘋果也推出了 AutoresizingMask,用來協調子檢視與父檢視之間的關係。再之後,各種各樣的 iPhone 和 iPad 紛紛面世,不僅僅是螢幕尺寸方面的差異,更有異形屏(iPhone X)。在此期間,蘋果提出了 AutoLayout 技術,供開發者進行螢幕適配。

使用 AutoLayout 的方法也有兩種——通過 Interface Builder 或者純程式碼。前者一直是蘋果官方文件裡所鼓勵的,原因是蘋果從最初到現在,對於 iOS 應用的想法都是小而美的,在他們的認知裡,一個 APP 應該提供儘可能小的功能集,這也是為為何蘋果迄今為止官方推薦的架構仍然是 MVC,官方推薦的開發方式仍是以 StoryBoard(Size Classes)。但是在一些專案較大的公司,StoryBoard 的某些特性(導致應用包過大,減緩啟動速度,合併程式碼困難)又是不能為人所容忍的,便有了純程式碼來實現 View 層的一群開發者(比如我)。

如果你曾經用程式碼來實現 AutoLayout,你會發現蘋果提供的 API 的繁瑣程度令人髮指,這也是 SnapKit 這類框架被髮明的原因。SnapKit 是一種使 iOSOS X 上的自動佈局更加簡單的 DSL。與親哥 Masonry(兩個框架都出自同一個團隊之手) 不一樣的是,SnapKit 更好的利用了 Swift 的一些語言特性,如果你是一個 Swift 開發者,那麼更應該優選 SnapKit

接下來,我們從 SnapKit 劃分好的各個模組來學習一下,不僅是學習如何更好的寫出一個框架,更多的是如何的寫好 Swift。本篇文章將帶領大家瞭解一下 Extensions 這個模組。

ConstraintView+Extensions

條件編譯

Swift 中沒有巨集定義的概念,很多依賴巨集來施展的小技巧都不能實現了。但是 Swift 還是保留了一些基礎的功能,來讓我們控制編譯流程和內容。例如:

#if os(iOS) || os(tvOS)
    import UIKit
#else
    import AppKit
#endif
複製程式碼

#if#elseif#elseendif 這套編譯標記在 Swift 中同樣可用,同時 Swift 還提供了 os() 這樣檢測系統平臺的函式,在這裡則是根據不同的作業系統選擇匯入不同的框架。更多內容可以參閱這篇文章:條件編譯

typealias

ConstraintView 這個類本身也是通過條件編譯來宣告的,同時用到了 typealias

#if os(iOS) || os(tvOS)
    public typealias ConstraintView = UIView
#else
    public typealias ConstraintView = NSView
#endif
複製程式碼

typealias 是一種給類增加別名等方法,它的一個用途是實現跨平臺的能力。ConstraintViewiOStvOS 平臺上表示 UIView,在其他平臺上則表示 NSView

@available

@available 用於函式、方法、類或協議的前面,表明平臺和作業系統適用性。

@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
複製程式碼

* 代表全平臺,同時還支援一些額外的引數:deprecated=版本號:從指定平臺某個版本開始過期該宣告,message=資訊內容:給出一些附加資訊。更多用法可以參考這篇文章:每週 Swift 社群問答:@available 和 #available

名稱空間

擴充套件之於 Swift 就好比分類之於 Objective-C,所以同樣可能遇到方法名衝突的可能。在 Objective-C 中,我們通過給方法名加字首來規避這一問題。但在 Swift 中,我們有更好的方法,例如:

public var snp: ConstraintViewDSL {
    return ConstraintViewDSL(view: self)
}
複製程式碼

通過計算屬性就可以做到避免擴充方法名衝突了,呼叫起來就像 view.snp.xxx 這樣,方便好用。

ConstraintLayoutGuide+Extensions

ConstraintLayoutGuide 是在不同的平臺上對 LayoutGuide 的不同表示:

#if os(iOS) || os(tvOS)
    @available(iOS 9.0, *)
    public typealias ConstraintLayoutGuide = UILayoutGuide
#else
    @available(OSX 10.11, *)
    public typealias ConstraintLayoutGuide = NSLayoutGuide
#endif
複製程式碼

UILayoutGuide 可以為我們生成一個虛擬的佔位物件,輔助我們來進行自動佈局。關於 UILayoutGuide 的常見用法,可以參考這篇文章:是時候瞭解一下UILayoutGuide了

UILayoutSupport+Extensions

ConstraintLayoutSupport 是在不同的平臺上對 UILayoutSupport 的不同表示:

#if os(iOS) || os(tvOS)
    @available(iOS 8.0, *)
    public typealias ConstraintLayoutSupport = UILayoutSupport
#else
    public class ConstraintLayoutSupport {}
#endif
複製程式碼

不過有所不同的是 APPKit 框架內並沒有對應的概念,所以在 #else 分支裡則定義了一個 ConstraintLayoutSupport 類,這也是跨平臺時的一種做法。

原文地址:SnapKit 原始碼解讀(一):Extensions

如果覺得我寫的還不錯,請關注我的微博@小橘爺,最新文章即時推送~

相關文章