RayWenderlich 官方 Swift 風格指南
來自專欄 iOS / Swift / OC
該文章由 iOSCaff 社區 組織翻譯,後續社區會保持文章的更新,如果你覺得這篇文章對你有幫助,歡迎到社區點贊支持。
譯文地址:https://ioscaff.com/topics/84/raywenderlich-official-swift-style-guide原文地址:https://github.com/raywenderlich/swift-style-guide
已更新到 Swift 3
這篇風格指南可能不同於你看到的其他風格指南。因為它的重點偏向於列印和網頁的可讀性。我們創建這篇風格指南的目的,是為了讓我們的書、教程和初學者套件中的代碼,在有很多作者同時寫書的情況下,也能保持規範與一致。
我們的首要目標是清晰、一致和簡潔。
正確性
努力讓你的代碼在沒有警告的情況下編譯。 這條規則決定了許多風格決策,比如使用 #selector 類型而不是字元串字面量。
命名
描述性和一致性的命名讓軟體更易於閱讀和理解。使用 API 設計規範 中描述的 Swift 命名規範。 一些關鍵點包括如下:
- 盡量讓調用的地方更加簡明
- 簡明性優先而不是簡潔性
- 使用駝峰命名法(而不是蛇形命名法)
- 針對類型(和協議)使用首字母大寫,其它都是首字母小寫
- 包含所有需要的單詞,同時省略不必要的單詞
- 基於角色的命名,而不是類型
- 有時候要針對弱引用類型信息進行補充
- 盡量保持流暢的用法
- 工廠方法以
make開頭 - 命名方法的副作用
- 不可變版本的動詞方法要遵循後接 -ed, -ing 的規則
- 可變版本的名詞方法要遵循 formX 的規則
- 布爾類型應該像斷言一樣讀取
- 描述 這是什麼 的協議應該讀作名詞
- 描述 一種能力 的協議應該以 -able 或者 -ible 結尾
- 使用不會讓專家驚訝或讓初學者迷惑的術語
- 通常要避免縮寫
- 使用名稱的先例
- 首選方法和屬性而不是自由函數
- 統一向上或向下包裝首字母縮略詞和首字母
- 為相同含義的方法提供相同的基本名稱
- 避免返回類型的重載
- 選擇用於文檔的好的參數名
- 為閉包和元組參數設置標籤
- 利用默認參數的優勢
文章
在文章中引用方法時,含義明確是至關重要的。儘可能用最簡單的形式引用方法。
- 寫一個不帶參數的方法。 舉例: 下一步,你需要調用方法
addTarget。 - 寫一個帶參數標籤的方法。 舉例: 下一步,你需要調用方法
addTarget(_:action:)。 - 寫一個帶參數標籤和類型的完整方法。 舉例: 下一步, 你需要調用方法
addTarget(_: Any?, action: Selector?)。
用上面的例子使用 UIGestureRecognizer, 1 是明確的,也是首選的。
專家提示: 你可以用 Xcode 的跳轉欄來查看帶有參數標籤的方法。
類前綴
Swift 的類自動被包含在模塊分配的命名空間中。不應該再添加類似於 RW 的類前綴。如果不同模塊的兩個命名衝突,可以在類名前添加模塊名來消除歧義。無論如何,僅在少數可能引起混淆的情況下指明模塊名。
import SomeModulelet myClass = MyModule.UsefulClass()
代理
當創建自定義代理方法的時候,未命名的第一個參數應該是代理源。 ( UIKit 包含很多這樣的例子。)
推薦:
func namePickerView(_ namePickerView: NamePickerView, didSelectName name: String)func namePickerViewShouldReload(_ namePickerView: NamePickerView) -> Bool
不推薦:
func didSelectName(namePicker: NamePickerViewController, name: String)func namePickerShouldReload() -> Bool
使用上下文推斷的類型
使用上下文推斷編譯器書寫更短更明確的代碼。(你也可以閱讀 類型推斷。)
推薦:
let selector = #selector(viewDidLoad)view.backgroundColor = .redlet toView = context.view(forKey: .to)let view = UIView(frame: .zero)
不推薦:
let selector = #selector(ViewController.viewDidLoad)view.backgroundColor = UIColor.redlet toView = context.view(forKey: UITransitionContextViewKey.to)let view = UIView(frame: CGRect.zero)
一般的
一般的類型參數應該是描述性的、大寫駝峰法命名。當類名沒有富有含義的關係或角色時,使用傳統的單個大寫字母來命名,例如 T 、 U 或 V。
推薦:
struct Stack<Element> { ... }func write<Target: OutputStream>(to target: inout Target)func swap<T>(_ a: inout T, _ b: inout T)
不推薦:
struct Stack<T> { ... }func write<target: OutputStream>(to target: inout target)func swap<Thing>(_ a: inout Thing, _ b: inout Thing)
語言
使用美式英語拼寫來匹配 Apple 的 API。
推薦:
let color = "red"
不推薦:
let colour = "red"
代碼組織
用擴展將代碼組織為功能邏輯塊。每個擴展都應該添加 // MARK: - 注釋,以保證代碼的結構清晰。
協議遵循
推薦為協議方法加一個單獨的擴展,尤其是為一個模型加入協議遵循的時候。這可以讓有關聯的協議方法被分組在一起,也可以簡化用類關聯方法向這個類添加協議的指令。
推薦:
class MyViewController: UIViewController { // 類填充在這}// MARK: - UITableViewDataSourceextension MyViewController: UITableViewDataSource { // table view 的數據源方法}// MARK: - UIScrollViewDelegateextension MyViewController: UIScrollViewDelegate { // scroll view 的代理方法}
不推薦:
class MyViewController: UIViewController, UITableViewDataSource, UIScrollViewDelegate { // 所有方法}
因為編譯器不允許在派生類中重新聲明協議遵循,所以並不總是需要複製基類的擴展組。如果派生類是一個終端類,並且只有少數方法會被覆蓋,那麼這個原則尤為正確。應由作者自行決定何時保留擴展組- 。
對於 UIKit 中的視圖控制器,可考慮將生命周期、自定義存取器和 IBAction 分組在單獨的類擴展中。
無用代碼
無用代碼(殭屍代碼),包括 Xcode 模板代碼和佔位注釋,應該被移除掉。教程或書籍中教用戶使用的注釋代碼除外。
僅實現簡單調用父類,但與教程無直接關聯的方法應該被移除。這裡包括任何為空的或無用的 UIApplicationDelegate 方法。
推薦:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return Database.contacts.count}
不推薦:
override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // 任何可以重建資源的處理。}override func numberOfSections(in tableView: UITableView) -> Int { // #warning 未完成的實現,返回節數。 return 1}override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // #warning 未完成的實現,返回行數。 return Database.contacts.count}
最小引用
引用最小化。舉個例子,引用 Foundation 就足夠的情況下不要再引用 UIKit 。
空格
- 用兩個字元縮進比用製表符縮進更節省空間,同時能防止換行。務必在 Xcode 和項目中設置這個偏好,如下所示:

- 方法大括弧和其他大括弧(
if/else/switch/while等)總是在和語句相同的行寫左括弧,而在新行寫右括弧。 - 提示:你可以通過選中一些代碼(或按 ?A 選中全部)然後按 Control-I (或在目錄中選擇編輯器 -> 結構 -> 重新縮進)的方式來重新縮進代碼。一些 Xcode 模板代碼會使用 4 個空格的製表符硬編碼,這就是一個修正它的好方法。推薦:
if user.isHappy { // 做一件事} else { // 做另一件事}
不推薦:
if user.isHappy{ // 做一件事}else { // 做另一件事}
- 方法之間應該只有一個空行,這樣有助於視覺清晰和組織。方法中的空白應該按功能分隔代碼,但在一個方法中有很多段意味著你應該將它們封裝進不同的方法。
- 冒號總是在左邊沒有空格而右邊有空格。比較特殊的是三元運算符
? :、空字典[:]和帶有未命名參數(_:)的#selector語法 .
推薦:
class TestDatabase: Database { var data: [String: CGFloat] = ["A": 1.2, "B": 3.2]}
不推薦:
class TestDatabase : Database { var data :[String:CGFloat] = ["A" : 1.2, "B":3.2]}
- 長行應該在 70 個字元左右被換行(這裡並非硬性限制,可自行調整)。
- 避免在行結尾的地方附上空白。
- 在每個文件的結尾處增加一個單獨的換行符。
注釋
需要的時候,用注釋來解釋一個特定的代碼片段 為什麼 做某件事。注釋應保持要麼是最新的,要麼就被刪除。
為了避免塊注釋和代碼內聯,代碼應該儘可能自文檔化。 例外:這不含那些注釋被用於生成文檔的情況 。
類和結構體
使用哪個?
請記住,結構體有 值語義。對沒有標識的事物應用結構體。一個包含 [a, b, c] 的數組和另一個包含 [a, b, c] 的數組是完全一樣的。他們是可以完全互換的。使用第一個數組還是第二個數組都無所謂,因為他們代表著完全相同的事物。這就是為什麼數組是結構體。
類有 引用語義。對有標識或有具體生命周期的事物應用類。你需要將人建模為一個類,因為不同兩個人對象是兩個不同的事物。只是因為兩個人擁有相同的名字和生日不意味著他們是同一個人。但是人的生日應該是一個結構體,因為 1950 年 3 月 3 日和任何其它的 1950 年 3 月 3 日日期對象是相同的。日期本身沒有標識。
有時,事物應該是結構體但需要遵循 AnyObject,或在歷史上已經被建模為類 (NSDate 、 NSSet)。儘可能嘗試遵循這些原則。
定義的舉例
這是一個風格良好的類定義例子:
class Circle: Shape { var x: Int, y: Int var radius: Double var diameter: Double { get { return radius * 2 } set { radius = newValue / 2 } } init(x: Int, y: Int, radius: Double) { self.x = x self.y = y self.radius = radius } convenience init(x: Int, y: Int, diameter: Double) { self.init(x: x, y: y, radius: diameter / 2) } override func area() -> Double { return Double.pi * radius * radius }}extension Circle: CustomStringConvertible { var description: String { return "center = (centerString) area = (area())" } private var centerString: String { return "((x),(y))" }}
上面的例子遵循了以下風格規範:
- 用後面有空格而前面沒有空格的冒號,為屬性、變數、常量、參數聲明和其它語句指定類型,例如:
x: Int和Circle: Shape。 - 如果多個變數和結構體共享一個共同的目的 / 上下文,則可以在同一行中定義。
- 縮進 getter、setter 的定義和屬性觀察器。
- 不要再添加如
internal的默認修飾符。類似的,當重寫一個方法時,不要再重複添加訪問修飾符。 - 在擴展中組織額外功能(例如列印)。
- 隱藏非共享的實現細節,例如
centerString在擴展中使用private訪問控制。
Self 的使用
為了簡潔,請避免使用 self 關鍵詞,Swift 不需要用它來訪問一個對象屬性或調用它的方法。
僅在編譯器需要時(在 @escaping 閉包或初始化函數中,消除參數與屬性的歧義)才使用 self。換句話說,如果不需要 self 就能編譯通過,則可以忽略它。
計算屬性
為了簡潔,如果一個計算屬性是只讀的,則可以忽略 get 子句。僅在提供了 set 子句的情況下才需要 get 子句。
推薦:
var diameter: Double { return radius * 2}
不推薦:
var diameter: Double { get { return radius * 2 }}
Final
在教程中將類或成員標記為 final 會從主題分散注意力,而且也沒必要。 儘管如此,final 的使用有時可以表明你的意圖,且值得你這樣做。在下面的例子中,Box 有特定的目的,且並不打算在派生類中自定義它。標記為 final 可以使它更清晰。
// 用這個 Box 類將任何一般類型轉換為引用類型。final class Box<T> { let value: T init(_ value: T) { self.value = value }}
方法聲明
在一行中保持較短的方法聲明,包括左括弧:
func reticulateSplines(spline: [Double]) -> Bool { // 在這裡寫網格代碼}
對於簽名較長的函數,則需在合適的位置換行,然後在後續的行中加一個額外的換行:
func reticulateSplines(spline: [Double], adjustmentFactor: Double, translateConstant: Int, comment: String) -> Bool { // 在這裡寫網路代碼}
閉包表達式
僅在參數列表最後有個單獨的閉包表達式參數時,使用尾隨閉包語法。給閉包參數定義一個描述性的命名。
推薦:
UIView.animate(withDuration: 1.0) { self.myView.alpha = 0}UIView.animate(withDuration: 1.0, animations: { self.myView.alpha = 0}, completion: { finished in self.myView.removeFromSuperview()})
不推薦:
UIView.animate(withDuration: 1.0, animations: { self.myView.alpha = 0})UIView.animate(withDuration: 1.0, animations: { self.myView.alpha = 0}) { f in self.myView.removeFromSuperview()}
對於上下文清晰的單獨表達式閉包,使用隱式返回:
attendeeList.sort { a, b in a > b}
使用尾隨閉包的鏈式方法應該清晰且在上下文中易讀。作者將自行抉擇空格、換行、命名與匿名參數的使用。舉例:
let value = numbers.map { $0 * 2 }.filter { $0 % 3 == 0 }.index(of: 90)let value = numbers .map {$0 * 2} .filter {$0 > 50} .map {$0 + 10}
類型
請儘可能多的使用 Swift 原生類型。 Swift 提供了 Objective-C 橋接,所以當你需要的時候你仍然可以使用全套方法。
推薦:
let width = 120.0 // Doublelet widthString = (width as NSNumber).stringValue // String
不推薦:
let width: NSNumber = 120.0 // NSNumberlet widthString: NSString = width.stringValue // NSString
在 Sprite Kit 代碼中,使用 CGFloat 可以讓你的代碼避免太多轉換,從而讓你的代碼更加簡潔。
常量
使用 let 關鍵字來定義常量,使用 var 關鍵字來定義變數。如果變數的值不會改變,則要使用 let 來代替 var 。
提示: 一個比較好的技巧就是定義所有的東西都使用 let , 當編譯器警告的時候再改為 var 。
你可以在一個類型裡面去定義常量而不是在類型的實例變數中去使用類型屬性。使用 static let 去聲明一個類型屬性作為常量。用這種方式聲明類型屬性比聲明全局變數更推薦,因為這種方式更能和實例屬性區分開。舉例:
推薦:
enum Math { static let e = 2.718281828459045235360287 static let root2 = 1.41421356237309504880168872}let hypotenuse = side * Math.root2
注意: 使用無大小寫枚舉的優勢,就是它不會被意外的實例化,而只是單純的作為一個命名空間。
不推薦:
let e = 2.718281828459045235360287 // 污染全局命名空間let root2 = 1.41421356237309504880168872let hypotenuse = side * root2 // 什麼 root2?
靜態方法和可變類型屬性
靜態方法和類型屬性跟全局函數和全局變數的工作原理類似,應當謹慎使用。當功能的作用域是一個特定類型或需要與 Objective-C 交互時,它們非常有用。
可選類型
在可接受 nil 值的情況下,使用 ? 聲明變數和函數返回類型為可選類型。
用 ! 聲明的隱式解包類型,僅用於稍後在使用前初始化的實例變數,比如將在 viewDidLoad 中創建子視圖。
當訪問一個可選值時,如果值僅被訪問一次或在鏈中有許多可選項時,使用可選鏈:
self.textContainer?.textLabel?.setNeedsDisplay()
當一次性解包和執行多個操作更方便時,使用可選綁定:
if let textContainer = self.textContainer { // 用 textContainer 做很多事情}
在命名可選變數和屬性時,需避免類似 optionalString 或 maybeView 這樣的命名,因為他們的可選性已經體現在類型聲明中了。
對於可選綁定,適當時使用原始名稱,而不是使用像 unwrappedView 或 actualLabel 這樣的名稱。
推薦:
var subview: UIView?var volume: Double?// later on...if let subview = subview, let volume = volume { // 使用展開的 subview 和 volume 做某件事}
不推薦:
var optionalSubview: UIView?var volume: Double?if let unwrappedSubview = optionalSubview { if let realVolume = volume { // 使用 unwrappedSubview 和 volume 做某件事 }}
延遲初始化
在更細粒度地控制對象聲明周期時考慮使用延遲初始化。 對於UIViewController ,延遲初始化視圖是非常正確的。你也可以直接調用 { }() 的閉包或調用私有工廠方法。例如:
lazy var locationManager: CLLocationManager = self.makeLocationManager()private func makeLocationManager() -> CLLocationManager { let manager = CLLocationManager() manager.desiredAccuracy = kCLLocationAccuracyBest manager.delegate = self manager.requestAlwaysAuthorization() return manager}
注意: - 因為沒有發生循環引用,所以這裡不需要 [unowned self]。
類型推斷
優先選擇簡潔緊湊的代碼,讓編譯器為單個實例的常量或變數推斷類型。類型推斷也適合於小(非空)的數組和字典。需要時,請指明特定類型,如 CGFloat 或 Int16。
推薦:
let message = "Click the button"let currentBounds = computeViewBounds()var names = ["Mic", "Sam", "Christine"]let maximumWidth: CGFloat = 106.5
不推薦:
let message: String = "Click the button"let currentBounds: CGRect = computeViewBounds()let names = [String]()
空數組和空字典的類型注釋
為空數組和空字典使用類型注釋。(對於分配給大型、多行文字的數組和字典,使用類型注釋。)
推薦:
var names: [String] = []var lookup: [String: Int] = [:]
不推薦:
var names = [String]()var lookup = [String: Int]()
注意:遵循此原則意味著選擇描述性命名比之前更重要。
語法糖
推薦使用類型聲明簡短的版本,而不是完整的泛型語法。
推薦:
var deviceModels: [String]var employees: [Int: String]var faxNumber: Int?
不推薦:
var deviceModels: Array<String>var employees: Dictionary<Int, String>var faxNumber: Optional<Int>
函數 vs 方法
不附屬於類或類型的自有函數應該被謹慎使用。可能的話,首選方法而不是自由函數。這有助於可讀性和易領悟性。
自由函數最適用於它們與任何特定類或實例無關的情況。
推薦:
let sorted = items.mergeSorted() // 容易領悟的rocket.launch() // 模型的行為
不推薦:
let sorted = mergeSort(items) // 難以領悟的launch(&rocket)
自由函數異常
let tuples = zip(a, b) // 作為自由函數感到自然(對稱)let value = max(x, y, z) // 另一個感到自然的自由函數
內存管理
代碼 (甚至非生產環境、教程演示的代碼)都不應該出現循環引用。分析你的對象圖並用 weak 和 unowned 來防止強循環引用。或者,使用值類型( struct、enum )來徹底防止循環引用。
延長對象的生命周期
使用慣用語法 [weak self] 和 guard let strongSelf = self else { return } 來延長對象的生命周期。 在 self 超出閉包生命周期不明顯的地方,[weak self] 更優於 [unowned self]。 明確地延長生命周期優於可選解包。
推薦:
resource.request().onComplete { [weak self] response in guard let strongSelf = self else { return } let model = strongSelf.updateModel(response) strongSelf.updateUI(model)}
不推薦:
// 如果在響應返回前 self 被釋放,則可能導致崩潰resource.request().onComplete { [unowned self] response in let model = self.updateModel(response) self.updateUI(model)}
不推薦:
// 內存回收可以發生在更新模型和更新 UI 之間resource.request().onComplete { [weak self] response in let model = self?.updateModel(response) self?.updateUI(model)}
訪問控制
在教程中,完整的訪問控制注釋會分散主題且是不必要的。然而,適時地使用 private 和 fileprivate 會使代碼更加清晰,也會有助於封裝。 在合理情況下,private 要優於 fileprivate。 使用擴展可能會要求你使用 fileprivate。
只有需要完整的訪問控制規範時,才顯式地使用 open 、 public 和 internal。
將訪問控制用作前置屬性說明符。僅有 static 說明符或諸如 @IBAction 、 @IBOutlet 和 @discardableResult 的屬性應該放在訪問控制前面。
推薦:
private let message = "Great Scott!"class TimeMachine { fileprivate dynamic lazy var fluxCapacitor = FluxCapacitor()}
不推薦:
fileprivate let message = "Great Scott!"class TimeMachine { lazy dynamic fileprivate var fluxCapacitor = FluxCapacitor()}
控制流
優先選擇for 循環的 for-in 格式而不是 while-condition-increment 格式。
推薦:
for _ in 0..<3 { print("Hello three times")}for (index, person) in attendeeList.enumerated() { print("(person) is at position #(index)")}for index in stride(from: 0, to: items.count, by: 2) { print(index)}for index in (0...3).reversed() { print(index)}
不推薦:
var i = 0while i < 3 { print("Hello three times") i += 1}var i = 0while i < attendeeList.count { let person = attendeeList[i] print("(person) is at position #(i)") i += 1}
黃金路徑
當使用條件語句編碼時,代碼的左邊距應該是 「黃金」或「快樂」的路徑。就是不要嵌套 if 語句。多個返回語句是可以的。guard語句就是因為這個創建的。
Preferred:
func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies { guard let context = context else { throw FFTError.noContext } guard let inputData = inputData else { throw FFTError.noInputData } // 用上下文和輸入計算頻率 return frequencies}
不推薦:
func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies { if let context = context { if let inputData = inputData { // 用上下文和輸入計算頻率 return frequencies } else { throw FFTError.noInputData } } else { throw FFTError.noContext }}
當用 guard 或 if let 解包多個可選值時,在可能的情況下使用最下化複合版本嵌套。舉例:
推薦:
guard let number1 = number1, let number2 = number2, let number3 = number3 else { fatalError("impossible")}// 用數字做某事
不推薦:
if let number1 = number1 { if let number2 = number2 { if let number3 = number3 { // 用數字做某事 } else { fatalError("impossible") } } else { fatalError("impossible") }} else { fatalError("impossible")}
失敗防護
對於用某些方法退出,防護語句是必要的。一般地,它應該是一行簡潔的語句,比如: return 、 throw 、 break 、 continue 和 fatalError()。應該避免大的代碼塊。如果清理代碼被用在多個退出點,則可以考慮用 defer 塊來避免清理代碼的重複。
分號
在 Swift 中,每條代碼語句後面都不需要加分號。只有在你希望在一行中結合多條語句,才需要加分號。
不要在用分號分隔的單行中寫多條語句。
推薦:
let swift = "not a scripting language"
不推薦:
let swift = "not a scripting language";
注:Swift 非常不同於 JavaScript。在 JavaScript 中忽略分號 一般被認為不安全。
括弧
條件周圍的括弧是不必要的,應該被忽略。
推薦:
if name == "Hello" { print("World")}
不推薦:
if (name == "Hello") { print("World")}
在更大的表達式中,可選括弧有時可以讓代碼讀起來更清晰。
推薦:
let playerMark = (player == current ? "X" : "O")
組織和包 ID
涉及到 Xcode 項目的地方,組織應該被設置為 Ray Wenderlich 並且包 ID 應該被設置為 com.razeware.TutorialName ,其中 TutorialName 是教程項目的名字。

版權聲明
以下版權聲明應該被包含在每個源文件的頂部:
/// Copyright (c) 2018 Razeware LLC/// /// Permission is hereby granted, free of charge, to any person obtaining a copy/// of this software and associated documentation files (the "Software"), to deal/// in the Software without restriction, including without limitation the rights/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell/// copies of the Software, and to permit persons to whom the Software is/// furnished to do so, subject to the following conditions:/// /// The above copyright notice and this permission notice shall be included in/// all copies or substantial portions of the Software./// /// Notwithstanding the foregoing, you may not use, copy, modify, merge, publish,/// distribute, sublicense, create a derivative work, and/or sell copies of the/// Software in any work that is designed, intended, or marketed for pedagogical or/// instructional purposes related to programming, coding, application development,/// or information technology. Permission for such use, copying, modification,/// merger, publication, distribution, sublicensing, creation of derivative works,/// or sale is expressly withheld./// /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN/// THE SOFTWARE.
笑臉
笑臉是網站 raywenderlich.com 非常突出的風格特點!正確使用微笑來表達對編碼主題的歡樂與興奮是非常重要的。使用右方括弧 ] 是因為它代表 ASCII 中的最大笑容。右括弧 ) 表示三心二意的笑臉,因此不推薦使用。
推薦:
:]
不推薦:
![]()
參考文獻
- Swift API 設計規範
- Swift 編程語言
- Swift 與 Cocoa 和 Objective-C 一起使用
- Swift 標準庫參考
iOSCaff 是一個面向 iOS 開發者的技術知識社區,致力於為開發者提供一個更加高效、便捷的學習環境。
推薦閱讀:
※xib設置label寬度或高度自適應文本
※IOS開發中Xcode的一些使用技巧你又知道多少呢?
※iOS 客戶端界面設計

