前言
iOS 開發(fā)中的布局方式,總體而言經(jīng)過了三個(gè)時(shí)代?;煦绯蹰_之時(shí),世間只有3.5英寸(iPhone 4、iPhone 4S),那個(gè)時(shí)候屏幕適配對(duì)于大多數(shù) iOS 開發(fā)者來說并不是什么難題,用 frame 就能精確高效的定位。這之后,蘋果發(fā)布了4英寸機(jī)型(iPhone 5、iPhone 5C、iPhone 5S),與此同時(shí)蘋果也推出了 AutoresizingMask,用來協(xié)調(diào)子視圖與父視圖之間的關(guān)系。再之后,各種各樣的 iPhone 和 iPad 紛紛面世,不僅僅是屏幕尺寸方面的差異,更有異形屏(iPhone X)。在此期間,蘋果提出了 AutoLayout 技術(shù),供開發(fā)者進(jìn)行屏幕適配。
使用 AutoLayout 的方法也有兩種——通過 Interface Builder 或者純代碼。前者一直是蘋果官方文檔里所鼓勵(lì)的,原因是蘋果從最初到現(xiàn)在,對(duì)于 iOS 應(yīng)用的想法都是小而美的,在他們的認(rèn)知里,一個(gè) APP 應(yīng)該提供盡可能小的功能集,這也是為為何蘋果迄今為止官方推薦的架構(gòu)仍然是 MVC,官方推薦的開發(fā)方式仍是以 StoryBoard(Size Classes)。但是在一些項(xiàng)目較大的公司,StoryBoard 的某些特性(導(dǎo)致應(yīng)用包過大,減緩啟動(dòng)速度,合并代碼困難)又是不能為人所容忍的,便有了純代碼來實(shí)現(xiàn) View 層的一群開發(fā)者(比如我)。
如果你曾經(jīng)用代碼來實(shí)現(xiàn) AutoLayout,你會(huì)發(fā)現(xiàn)蘋果提供的 API 的繁瑣程度令人發(fā)指,這也是 SnapKit 這類框架被發(fā)明的原因。SnapKit 是一種使 iOS 和 OS X 上的自動(dòng)布局更加簡單的 DSL。與親哥 Masonry(兩個(gè)框架都出自同一個(gè)團(tuán)隊(duì)之手) 不一樣的是,SnapKit 更好的利用了 Swift 的一些語言特性,如果你是一個(gè) Swift 開發(fā)者,那么更應(yīng)該優(yōu)選 SnapKit。
接下來,我們從 SnapKit 劃分好的各個(gè)模塊來學(xué)習(xí)一下,不僅是學(xué)習(xí)如何更好的寫出一個(gè)框架,更多的是如何的寫好 Swift。本篇文章將帶領(lǐng)大家了解一下 Extensions 這個(gè)模塊。
ConstraintView+Extensions
條件編譯
Swift 中沒有宏定義的概念,很多依賴宏來施展的小技巧都不能實(shí)現(xiàn)了。但是 Swift 還是保留了一些基礎(chǔ)的功能,來讓我們控制編譯流程和內(nèi)容。例如:
#if os(iOS) || os(tvOS)
import UIKit
#else
import AppKit
#endif
#if、#elseif、#else 和 endif 這套編譯標(biāo)記在 Swift 中同樣可用,同時(shí) Swift 還提供了 os() 這樣檢測(cè)系統(tǒng)平臺(tái)的函數(shù),在這里則是根據(jù)不同的操作系統(tǒng)選擇導(dǎo)入不同的框架。更多內(nèi)容可以參閱這篇文章:條件編譯。
typealias
ConstraintView 這個(gè)類本身也是通過條件編譯來聲明的,同時(shí)用到了 typealias
#if os(iOS) || os(tvOS)
public typealias ConstraintView = UIView
#else
public typealias ConstraintView = NSView
#endif
typealias 是一種給類增加別名等方法,它的一個(gè)用途是實(shí)現(xiàn)跨平臺(tái)的能力。ConstraintView 在 iOS 和 tvOS 平臺(tái)上表示 UIView,在其他平臺(tái)上則表示 NSView。
@available
@available 用于函數(shù)、方法、類或協(xié)議的前面,表明平臺(tái)和操作系統(tǒng)適用性。
@available(*, deprecated:3.0, message:"Use newer snp.* syntax.")
* 代表全平臺(tái),同時(shí)還支持一些額外的參數(shù):deprecated=版本號(hào):從指定平臺(tái)某個(gè)版本開始過期該聲明,message=信息內(nèi)容:給出一些附加信息。更多用法可以參考這篇文章:每周 Swift 社區(qū)問答:@available 和 #available
命名空間
擴(kuò)展之于 Swift 就好比分類之于 Objective-C,所以同樣可能遇到方法名沖突的可能。在 Objective-C 中,我們通過給方法名加前綴來規(guī)避這一問題。但在 Swift 中,我們有更好的方法,例如:
public var snp: ConstraintViewDSL {
return ConstraintViewDSL(view: self)
}
通過計(jì)算屬性就可以做到避免拓展方法名沖突了,調(diào)用起來就像 view.snp.xxx 這樣,方便好用。
ConstraintLayoutGuide+Extensions
ConstraintLayoutGuide 是在不同的平臺(tái)上對(duì) 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 可以為我們生成一個(gè)虛擬的占位對(duì)象,輔助我們來進(jìn)行自動(dòng)布局。關(guān)于 UILayoutGuide 的常見用法,可以參考這篇文章:是時(shí)候了解一下UILayoutGuide了
UILayoutSupport+Extensions
ConstraintLayoutSupport 是在不同的平臺(tái)上對(duì) UILayoutSupport 的不同表示:
#if os(iOS) || os(tvOS)
@available(iOS 8.0, *)
public typealias ConstraintLayoutSupport = UILayoutSupport
#else
public class ConstraintLayoutSupport {}
#endif
不過有所不同的是 APPKit 框架內(nèi)并沒有對(duì)應(yīng)的概念,所以在 #else 分支里則定義了一個(gè) ConstraintLayoutSupport 類,這也是跨平臺(tái)時(shí)的一種做法。
原文地址:SnapKit 源碼解讀(一):Extensions
如果覺得我寫的還不錯(cuò),請(qǐng)關(guān)注我的微博@小橘爺,最新文章即時(shí)推送~