前言
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
是一種使 iOS
和 OS 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
、#else
和 endif
這套編譯標記在 Swift
中同樣可用,同時 Swift
還提供了 os()
這樣檢測系統平臺的函式,在這裡則是根據不同的作業系統選擇匯入不同的框架。更多內容可以參閱這篇文章:條件編譯。
typealias
ConstraintView
這個類本身也是通過條件編譯來宣告的,同時用到了 typealias
#if os(iOS) || os(tvOS)
public typealias ConstraintView = UIView
#else
public typealias ConstraintView = NSView
#endif
複製程式碼
typealias
是一種給類增加別名等方法,它的一個用途是實現跨平臺的能力。ConstraintView
在 iOS
和 tvOS
平臺上表示 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
如果覺得我寫的還不錯,請關注我的微博@小橘爺,最新文章即時推送~