本文我在學習Swift的一些隨筆記錄,結構可能有點隨意,因爲處於學習階段因此僅供參考。前端
一、什麼是Swift語言?程序員
Swift是Apple在WWDC2014所發佈的一門編程語言,用來撰寫OS X和iOS應用程序[1]。在設計Swift時.就有意和Objective-C共存,Objective-C是Apple操做系統在導入Swift前使用的編程語言編程
Swift是供iOS和OS X應用編程的新編程語言,基於C和Objective-C,而卻沒有C的一些兼容約束。Swift採用了安全的編程模式和添加現代的功能來使得編程更加簡單、靈活和有趣。界面則基於廣受人民羣衆愛戴的Cocoa和Cocoa Touch框架,展現了軟件開發的新方向swift
/*雖然Swift是一個全新的語言,但與Objective-C和C卻有着千絲萬縷的關係,Swift其實就是Objective-C的文本變種,對於這門全新的語言,蘋果作的工做其實遠沒有想像的艱鉅。LLVM編譯器作工做只是先把swift翻譯成Objctive-C代碼,而後再把Objective-C代碼翻譯成C語言代碼,而後再把C語言代碼翻譯成彙編,最終翻譯成機器碼。*/api
二、Swift的特色。安全
Swift是Objective-C語言的一種替代方法,它採用現代編程語言理論概念並致力於提供更簡單的語法。在它的介紹中,它被簡單地描述爲「沒有C的Objective-C」。網絡
默認狀況下,Swift不公開指針和其餘不安全的訪問器,與Objective-C不一樣,它使用指針來廣泛引用對象實例。此外,Objective-C使用相似Smalltalk的語法來進行方法調用,已被其餘常見的面向對象(OO)語言(如Java或C#)的程序員更熟悉的點符號樣式和名稱空間系統所取代。Swift引入了真正的命名參數並保留了關鍵的Objective-C概念,包括協議,閉包和類別,一般用更簡潔的版本替換之前的語法,並容許將這些概念應用於其餘語言結構,如枚舉類型。多線程
語法糖閉包
在Cocoa和Cocoa Touch環境下,許多常見類都是Foundation Kit庫的一部分。這包括NSString字符串庫(使用Unicode),NSArray和NSDictionary集合類等。Objective-C提供了各類語法糖來容許這些對象在語言中即時建立,但一旦建立,對象就會被對象調用。例如,在Objective-C中鏈接兩個NSString所需的方法調用與此相似:app
NSString * str = @「hello,」 ;
str = [ str stringByAppendingString :@「world」 ];
在Swift中,這些基本類型中的不少都被提高爲語言的核心,而且能夠直接操縱。例如,字符串不可見地橋接到NSString(當導入Foundation時),如今能夠與+運算符串聯,從而容許大大簡化語法;
var str = 「hello」
Str += 「world」
庫、運行和開發
Swift語言出來後,可能新的項目直接使用swift來開發,但可能在過程當中會遇到一些狀況,某些已用OC寫好的類或封裝好的模塊,不想再在swift 中再寫一次,或者有一些第三方使用OC寫的,怎麼辦?那就使用混編。
Swift使用與現存的Objective-C系統相同的運行時,但須要iOS 7或macOS 10.9或更高版本。Swift和Objective-C代碼能夠在一個程序中使用,也能夠在擴展中使用C和C++。與C不一樣的是,C++代碼不能直接從Swift中使用。必須在Swift和C++之間建立一個Objective-C或C包裝器。在Objective-C中,Swift能夠很好地訪問對象模型,而且能夠用來子類化、擴展和使用Objective-C代碼來提供協議支持。相反的說法是不正確的:一個敏捷的類不能在Objective-C中被子類。
爲了幫助開發這些程序,以及重用現存的代碼,Xcode 6提供了一個半自動化系統,它構建並維護一個橋接頭,以便將Objective-C代碼暴露給Swift。這採用了額外的頭文件的形式,它簡單地定義或導入了項目Swift代碼所須要的全部Objective-C符號。在這一點上,Swift能夠引用這些導入中聲明的類型、函數和變量,就好像它們是用Swift編寫的。Objective-C代碼也能夠直接使用Swift代碼,經過導入一個自動維護的頭文件,其中包含了項目的Swift符號的Objective-C聲明。例如,一個名爲「MyApp」的混合項目中的Objective-C文件可使用代碼導入「MyApp-swift.h」來訪問Swift類或函數。然而,並非全部的符號均可以經過這種機制得到,可是使用諸如泛型類型、非對象可選類型、複雜的枚舉,甚至Unicode標識符之類的特定特性可能會使Objective-C沒法訪問。
Swift對屬性、由開發環境讀取的元數據的支持也有限,並且並不必定是編譯後的代碼的一部分。和Objective-C同樣,屬性使用@語法,可是當前可用的集合是很小的。其中一個例子是@iboutlet屬性,它將代碼中的給定值標記爲outlet,可在Interface Builder(IB)中使用。outlet是一種設備,它將屏幕顯示的值綁定到代碼中的對象
三、Swift的編譯過程
Swift 經由 LLVM,編譯成LLVM中間碼,最後編譯成本地機器代碼(二進制)。目前運行的時候會依賴 Objective-C Runtime。
一、解析:首先經過解析器模塊把源碼轉換爲沒有任何語義或類型信息的抽象語法樹(AST),而且針對輸入源的語法問題發出警告或者錯誤。
二、語義分析:負責解析AST並將其格式轉換爲便於檢查的AST,便於爲源代碼中的語義問題發出警告或者錯誤。
三、Clang導入器:負責導入Clang模塊並將他們導出的C或OCAPI映射到其對應的Swift API中。
四、SIL生成(Swift中間語言):負責將AST轉換成原始的SIL.
五、SIL轉換:負責將原始的SIL轉換成須要的規範的SIL格式。
六、SIL優化:爲程序執行額外的高級Swift進行特定的優化,包括自動引用計數優化,
虛擬化和泛型專業化等。
七、LLVM IR生成:將SIL轉換爲LLVM IR,此時LLVM能夠繼續對其進行優化而且生成機器碼。
四、Swift編譯命令詳解
MODES:
-dump-ast Parse and type-check input file(s) and dump AST(s) 解析輸入文件並轉儲AST並進行類型檢查(支持多文件)
-dump-parse Parse input file(s) and dump AST(s) 解析輸入文件並轉儲AST(支持多文件)
-dump-scope-maps <expanded-or-list-of-line:column>
Parse and type-check input file(s) and dump the scope map(s) 解析和類型檢查輸入文件,並轉儲範圍映射(s)
-dump-type-refinement-contexts
Type-check input file(s) and dump type refinement contexts(s)
-emit-assembly Emit assembly file(s) (-S) 發表裝配文件
-emit-bc Emit LLVM BC file(s) 發表 LLVM BC 文件
-emit-executable Emit a linked executable 發表相關的可執行文件
-emit-imported-modules Emit a list of the imported modules 發出導入的模塊列表
-emit-ir Emit LLVM IR file(s) 發表 LLVM IR 文件
-emit-library Emit a linked library 發表一個連接庫
-emit-object Emit object file(s) (-c)
-emit-sibgen Emit serialized AST + raw SIL file(s) 發佈序列AST 生成sil文件
-emit-sib Emit serialized AST + canonical SIL file(s) 發佈序列AST 生成規範的sil文件
-emit-silgen Emit raw SIL file(s) 發表原始的sil
-emit-sil Emit canonical SIL file(s) 發表規範的sil
-index-file Produce index data for a source file 爲源文件生成索引數據
-parse Parse input file(s)
-print-ast Parse and type-check input file(s) and pretty print AST(s)
-typecheck Parse and type-check input file(s)
OPTIONS:
-api-diff-data-file <path>
API migration data is from <path> 遷移數據從path
-application-extension Restrict code to those available for App Extensions
-assert-config <value> Specify the assert_configuration replacement. Possible values are Debug, Release, Unchecked, DisableReplacement.
-continue-building-after-errors
Continue building, even after errors are encountered 發生錯誤能夠繼續編譯
-disable-migrator-fixits
Disable the Migrator phase which automatically applies fix-its 禁止遷移 fix-its
-driver-time-compilation
Prints the total time it took to execute all compilation tasks 打印執行全部編譯程序的時間
-dump-migration-states-dir <path>
Dump the input text, output text, and states for migration to <path> 把輸入、輸出和狀態文本遷移到path
-dump-usr Dump USR for each declaration reference 把每一個聲明引用轉存到USR
-D <value> Marks a conditional compilation flag as true 將條件編譯標誌標記爲true
-embed-bitcode-marker Embed placeholder LLVM IR data as a marker 嵌入佔位符LLVM IR數據做爲標記
-embed-bitcode Embed LLVM IR bitcode as data將LLVM IR 的比特碼做爲數據嵌入
-emit-dependencies Emit basic Make-compatible dependencies files
-emit-loaded-module-trace-path <path>
Emit the loaded module trace JSON to <path>
-emit-loaded-module-trace
Emit a JSON file containing information about what modules were loaded 發佈一個JSON文件裏面包含加載的模塊信息
-emit-module-path <path>
Emit an importable module to <path> 發出一個可輸入的模塊 到 path路徑下
-emit-module Emit an importable module 發出一個可輸入的模塊
-emit-objc-header-path <path>
Emit an Objective-C header file to <path> 生成OC頭文件 到 指定路徑下
-emit-objc-header Emit an Objective-C header file
-emit-tbd-path <path> Emit the TBD file to <path>
-emit-tbd Emit a TBD file
-enforce-exclusivity=<enforcement>
Enforce law of exclusivity
-fixit-all Apply all fixits from diagnostics without any filtering 不須要任何過濾就能夠將全部的fixits應用於診斷。
-framework <value> Specifies a framework which should be linked against
-Fsystem <value> Add directory to system framework search path
-F <value> Add directory to framework search path
-gdwarf-types Emit full DWARF type info.
-gline-tables-only Emit minimal debug info for backtraces only
-gnone Don't emit debug info
-g Emit debug info. This is the preferred setting for debugging with LLDB.
-help Display available options
-import-underlying-module
Implicitly imports the Objective-C half of a module
-index-file-path <path> Produce index data for file <path>
-index-store-path <path>
Store indexing data to <path>
-I <value> Add directory to the import search path 將目錄添加到導入搜索路徑
-j <n> Number of commands to execute in parallel
-L <value> Add directory to library link search path
-l<value> Specifies a library which should be linked against
-migrate-keep-objc-visibility
When migrating, add '@objc' to declarations that would've been implicitly visible in Swift 3
-migrator-update-sdk Does nothing. Temporary compatibility flag for Xcode.
-migrator-update-swift Does nothing. Temporary compatibility flag for Xcode.
-module-cache-path <value>
Specifies the Clang module cache path
-module-link-name <value>
Library to link against when using this module
-module-name <value> Name of the module to build 要構建的模塊的名稱
-nostdimport Don't search the standard library import path for modules
-num-threads <n> Enable multi-threading and specify number of threads 啓用多線程並指定線程數
-Onone Compile without any optimization 編譯且沒有任何優化
-Ounchecked Compile with optimizations and remove runtime safety checks 編譯且優化 移除運行時安全檢查
-output-file-map <path> A file which specifies the location of outputs 指定輸出的文件位置
-O Compile with optimizations 編譯優化
-o <file> Write output to <file> 寫到指定文件
-parse-as-library Parse the input file(s) as libraries, not scripts 將輸入文件解析爲庫,不是腳本
-parse-sil Parse the input file as SIL code, not Swift source 將輸入文件解析爲sil(swift中見文件)
-parseable-output Emit textual output in a parseable format
-profile-coverage-mapping
Generate coverage data for use with profiled execution counts 生成用於提交執行計數的覆蓋率數據
-profile-generate Generate instrumented code to collect execution counts 生成用於收集執行計數的檢測代碼
-sanitize-coverage=<type>
Specify the type of coverage instrumentation for Sanitizers and additional options separated by commas
-sanitize=<check> Turn on runtime checks for erroneous behavior. 在運行時檢查錯誤
-save-temps Save intermediate compilation results 保存中間編譯結果
-sdk <sdk> Compile against <sdk>
-serialize-diagnostics Serialize diagnostics in a binary format 以二進制格式序列化
-static-executable Statically link the executable 可執行的靜態連接
-static-stdlib Statically link the Swift standard library Swift標準庫的靜態連接
-suppress-warnings Suppress all warnings 抑制全部警告
-swift-version <vers> Interpret input according to a specific Swift language version number 輸出當前Swift的版本號
-target-cpu <value> Generate code for a particular CPU variant 爲特定的CPU變量生成代碼
-target <value> Generate code for the given target 爲給定目標生成代碼
-tools-directory <directory>
Look for external executables (ld, clang, binutils) in <directory>
-use-ld=<value> Specifies the linker to be used 指明要使用的連接器
-verify-debug-info Verify the binary representation of debug output.
-version Print version information and exit
-v Show commands to run and use verbose output
-warn-swift3-objc-inference-complete
Warn about deprecated @objc inference in Swift 3 for every declaration that will no longer be inferred as @objc in Swift 4
-warn-swift3-objc-inference-minimal
Warn about deprecated @objc inference in Swift 3 based on direct uses of the Objective-C entrypoint
-warnings-as-errors Treat warnings as errors 將警告視爲錯誤
-whole-module-optimization
Optimize input files together instead of individually
-Xcc <arg> Pass <arg> to the C/C++/Objective-C compiler
-Xlinker <value> Specifies an option which should be passed to the linker
例:swiftc -dump-ast /users/code/a.swift > 1.txt //轉儲帶有類型檢查的a.swift語法樹
注:中文有些是直譯過來的因此有些描述可能不是特別準確
五、Swift包管理器
Swift 包管理器的正式發佈是隨着 Swift3.0 一塊兒發佈的,它是一個用於構建可以運行在 macOS 和 Linux 上的 Swift 庫和 app 的新方法。它可以幫助你管理依賴,讓你輕鬆構建、測試和運行你的 Swift 代碼。
Swift 包管理器有助於極大地改進 Swift 生態系統,讓 Swift 更容易使用、部署到沒有 Xcode 的平臺上,好比 Linux。Swift 包管理器還能解決在使用多個相互依賴的庫時的「依賴地獄」的問題。
注:」依賴地獄」又被稱做相依性地獄(英語:dependency hell),是指在操做系統中因爲軟件之間的依賴性不能被知足而引起的問題。一個軟件包依賴於其它必要的軟件包(且版本要匹配要求),使得軟件包系統造成了複雜的依賴關係網絡,並可能引起一系列問題。一些軟件包可能由於依賴性沒法知足,須要安裝大量軟件包;另外一方面,一個軟件包的卸載可能引起數量衆多的軟件包沒法工做。
Swift包之間的依賴關係離不開package.swift這個文件
Package.swift文件格式參考
Package(
name:String,
pkgConfig:String ? = nil,
providers:[SystemPackageProvider] ? = nil,
products:[Product] = [],
dependencies:[Dependency] = [],
targets:[Target] = [],
swiftLanguageVersions:[ Int ] ? = nil
)
解釋:
- name: 包名
- pkgConfig: 用於獲取系統模塊附加標誌的pkg-config(.pc)文件的名稱
- providers: 定義提示以顯示安裝系統模塊。
- products:包裝出售的產品。
- dependencies: 外部程序包依賴關係,不包括基礎庫
- targets: 包中的目標列表
- swiftLanguageVersions: swift語言版本
在語法樹中能夠經過 import_decl節點讀取依賴的包名
六、Swift前端入門
前面咱們知道編譯一個Swift文件須要的命令是swiftc hello.swift,因爲swiftc不包含-frontend因此他會被分解成自做業,swiftc hello.swift -driver-print-jobs
子做業以下:
第一個job調用-frontend命令 生成hello.o 而後經過連接器 ld把/tmp/hello.o鏈接到名字hello的可執行文件中。
這個命令輸出的是一個無類型的語法樹,它與swiftc -dump-parse hello.swift是相同的以下圖:
下面展現的是有類型語法樹的特色可使用命令 swiftc -dump-ast hello.swift輸出以下圖 :
無類型語法樹的特色是unresolved_decl_ref_expr節點,而且許多節點都是type = ‘<null>’值。
前面說到編譯會調用-frontend命令,那麼他是怎麼執行的呢,
如圖是tools/driver/driver.cpp中main函數裏面的代碼它會讀取命令中的第一個參數並且必須是第一個參數判斷是否是-frontend,而後調用perfromFrontend函數(它是一個工具方法/lib/FrontendTool)
Swift前端語法的讀取和大多數前端沒有任何區別,都是把一個Swift文件分割成n個Token而後循環讀取Token來解析Swift文件,循環結束的標識爲EOF。
例如:print(「hello world!」)解析的Token以下圖