## Objective-C代碼
### 一、布局規范
#### 1、頭文件引入
按照一定順序引入頭文件
```
#import <系統庫>
#import <第三方>
#import "項目類"
```
#### 2、屬性 和 私有變量
public 和 非public 屬性建議放在相應的地方
```
@interface ClassA ()
@property (nonatomic,strong) NSString *name;
@end
```
私有變量建議命名遵循其中一個,為了規避iOS的命名,特性個人推薦第二種方法命名私有變量
```
NSString *_title;
NSString *title_;
```
#### 3、類內部布局
```
#pragma mark - lifeCycle (這部分寫生命周期方法)
#pragma mark - <UITableViewDelegate> (系統的delegate方法)
#pragma mark - <CustomDelegate> (自定義的delegate方法)
#pragma mark - event response (交互方法)
#pragma mark - private methods (非公共方法)
#pragma mark - view getter(lazy) (主要是View懶加載)
#pragma mark - view setter
#pragma mark - data getter
#pragma mark - data setter
```
這個根據具體類的情況去自己可以增刪
對于private methods 和 event response 等等只是在本類中調用的方法建議以p_開頭,以后修改的時候能了解修改會造成的影響范圍
例如:
```
#pragma mark -private methods
- (void)p_didSelectQuestionItem:(NSDictionary *)questionItem
#pragma mark -event response
- (void)p_searchEventClick:(UIButton *)button
```
### 二、注釋
> 添加必要的注釋
>
* 所有的property 需要給出注釋;
>
* 所有自定義的方法需要給出注釋;
>
* 比較大的代碼塊需要給出注釋;
>
* 所有代碼中出現的阿拉伯數字需要給出注釋;
>
* 程序中出現加密/解密 邏輯的操作地方,需要給出注釋說明過程(無論是系統還是自定義)。
#### 1、每個類頭部有自己的獨白 比如一個viewController是用來做什么的 可以首先寫個注釋說明下 其他的類雷同
```
/**
這是一個用來測試注釋的viewController
注意點:
設計思路:
等等吧 你想說的告白都在這里
*/
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
{
}
- (void)viewDidLoad {
[super viewDidLoad];
}
@end
```
#### 2、單行,多行注釋
單行注釋 //+說明
```
// 初始化默認數據
[self p_setupDefaultData];
```
多行 /* */
```
/*!
XXX的狀態
- XXXType_1: 孩子找媽媽中
- XXXType_1: 孩子找爸爸中
- XXXType_1: 孩子找小朋友中
*/
typedef NS_ENUM(NSUInteger,XXXType) {
XXXType_1,
XXXType_2,
XXXType_3,
};
```
方法注釋
Commond+option+/
```
/**
向某人默認打招呼
@param name 某人
*/
- (void)sayHelloToPeople:(NSString *)name{
}
```
TODO標記
//TODO:XXX
用//TODO去做一些值得注意 或者 自己未完成的標志
```
- (void)sayHelloToPeople:(NSString *)name{
//TODO:向某人打招呼邏輯
}
```
### 三、一些縮進
#### 1、縮進
方法之間保留一行空行,
方法和屬性的格式請按照以下格式書寫:
```
- (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath;
```
```
- (void)viewDidLoad {
[super viewDidLoad];
}
```
```
@property (nonatomic, strong, readonly, nullable) NSIndexPath *previouslyFocusedIndexPath;
```
### 四、常見注意點:
- 盡量避免在程序中直接出現常數,使用超過一次的應以宏定義或枚舉的形式來替代。
- 常數的宏定義應與它實際使用時的類型相一致。如以3.0來定義浮點類型,用3表示整型。常量的命名應當能夠表達出它的用途,并且用大寫字母表示。例如:#definePI 3.1415926
- 刪除多余的空行、注釋、方法以及未被使用的資源文件。
```
UIKIT_EXTERN NSNotificationName const UIKeyboardWillShowNotification;
```
```
UIKIT_EXTERN NSString *const UIKeyboardFrameBeginUserInfoKey
```
```
typedef NS_ENUM(NSInteger, NSWritingDirectionFormatType) {
NSWritingDirectionEmbedding = (0 << 1),
NSWritingDirectionOverride = (1 << 1)
}
```
```
typedef NSString * NSAttributedStringDocumentReadingOptionKey
```
---
---
## Swift 編程規范
> 良好的編程規范有利于項目的維護,同時也能避免因人為的疏忽產生的錯誤。本篇編碼規范主要參考了 [swift-style-guide](https://github.com/raywenderlich/swift-style-guide/blob/master/README.markdown)和[The Swift Programming Language](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/index.html)當中的規范,并綜合了實際開發中總結的經驗。
### 正確性 (Correctness)
力爭讓你的代碼沒有編譯警告(`warning`)。這個規則下延伸出了許多決定,如:使用`#selector`方式,而不是直接使用字符串。
### 命名 (Naming)
描述性和一致性的命名使得代碼更易讀、更易懂。一些規則如下:
* 追求調用方的清晰性
* 優先使用更清晰的命名,而不是更簡潔的
* 使用駝峰樣式
* 類型、協議名首字母大寫,其他的都首字母小寫
* 包含所有需要的單詞,省略不必要的
* 使用基于角色的命名,而不是基于類型的
* 工廠方法使用`make`開頭
* 對方法的命名
* 動詞方法以`-ed`結尾,對于不可變的(`non-mutating`)動詞方法用`-ing`結尾
* 布爾類型(`boolean`)應該以`is`開頭
* 用于描述事物的協議(`protocols`)名稱,用名詞命名
* 用于描述能力的協議(`protocols`)名稱,應以`-able` 或 `-ible`結尾
* 不要用生僻的單詞
* 通常不要用縮寫
* 選用好的參數名來起到描述的作用
#### 類前綴 (Class Prefixes)
Swift中的類型自動使用了其所在的模塊(`module`)作為命名空間(`namespace`),所以你不必給類型加前綴。如果來自不同模塊的類型名子沖突,可以顯示的使用模塊名作為調用前綴來避免沖突。
```swift
import SomeModule
import OtherModule
let someUsefulClass = SomeModule.UsefulClass()
let otherUsefulClass = OtherModule.UsefulClass()
```
#### 代理 (Delegates)
當定義一個代理方法時,第一個匿名參數應該是代理的源對象。(`UIKit`中有許多這樣的的例子)
**推薦:**
```swift
func namePickerView(_ namePickerView: NamePickerView, didSelectName name: String)
func namePickerViewShouldReload(_ namePickerView: NamePickerView) -> Bool
```
**不推薦:**
```swift
/// `namePicker`應該是匿名的
func didSelectName(namePicker: NamePickerViewController, name: String)
/// 至少應包含`_ namePickerView: NamePickerView`參數,來作為代理的源對象
func namePickerShouldReload() -> Bool
```
#### 使用可類型推導的上下文 (Use Type Inferred Context)
利用好編譯器的類型推導特性,來寫出簡短、清晰的代碼。
**推薦:**
```swift
let selector = #selector(viewDidLoad)
view.backgroundColor = .red
let toView = context.view(forKey: .to)
let view = UIView(frame: .zero)
```
**不推薦:**
```swift
// 以下幾種寫法,都沒有用到編譯器的類型推導特性,寫出來的代碼較冗余
let selector = #selector(ViewController.viewDidLoad)
view.backgroundColor = UIColor.red
let toView = context.view(forKey: UITransitionContextViewKey.to)
let view = UIView(frame: CGRect.zero)
```
#### 泛型 (Generics)
泛型參數(`generic type parameters`)應當使用具有描述性的駝峰樣式來命名。當泛型參數不具有明確的關系或角色時,可使用一個大寫的字母表示即可。如:`T`,`U`,`V`
#### 使用的語言 (Language)
應使用美式英語的拼寫方式以匹配Apple的API,應盡量保持命名的可讀性,不應該用多含義且有相反或者混淆意思的單詞。
**推薦:**
```swift
let color = "red"
```
**不推薦:**
```swift
let colour = "red"
```
### 代碼組織 (Code Organization)
盡可能的使用擴展(`extensions`)來解耦你的代碼,將代碼劃分到不同的擴展模塊中,每個擴展應以`// MARK: -`開頭,來更好的區分擴展。
#### 協議的遵守 (Protocol Conformance)
具體來講,當讓一個`Model`遵守某個協議時,推薦添加一個獨立的`Model`擴展(`extensions`)來遵守該協議。這樣使得相關的協議方法能組織在一起。
**推薦:**
```swift
class MyViewController: UIViewController {
// class stuff here
}
// MARK: - UITableViewDataSource
extension MyViewController: UITableViewDataSource {
// table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewController: UIScrollViewDelegate {
// scroll view delegate methods
}
```
**不推薦:**
```swift
class MyViewController: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
// all methods
}
```
對于`UIKit`的視圖控制器(`view controllers`),可以考慮將生命周期(`lifecycle`)相關、自定義訪問器(`custom accessors`)、`IBAction`獨立不同的到類擴展中。
#### 無用的代碼 (Unused Code)
無用的代碼包括Xcode產生的模板代碼、占位的注釋等、方法的默認實現僅僅是調用`super`等,這些都應當移除掉。
**推薦:**
```swift
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Database.contacts.count
}
```
**不推薦:**
```swift
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return Database.contacts.count
}
```
#### 減小引入 (Minimal Imports)
保存最小的引入(`imports`)。例如, 當只使用`Foundation`時,不要引入`UIKit`。
### 空格 (Spacing)
* 代碼折行使用4個空格(`spaces`)
* 方法的大括號和其他大括號(`if`/`else`/`switch`/`while`等),其左括號必須要和語句在同一行,并且右括號要換行;
* 變量類型和冒號(:)之間保留一個空格;
* 返回值標記`->`兩側各保留一個空格;
**推薦:**
```swift
if user.isHappy {
// Do something
} else {
// Do something else
}
```
**不推薦:**
```swift
if user.isHappy
{
// Do something
}
else {
// Do something else
}
```
* 各個方法之間必須有一個空行,這使得代碼視覺上更清晰。
* 方法的實現中,應當適當的添加空行來劃分功能。過多的空行意味著你應該拆分這些功能到不同的方法中,通過這樣來避免一個巨大的方法。
* 通常冒號(Colons)的左邊應當沒有空格,而在右邊有一個空格。
例外:
1. 三目運算符(`ternary operator`) `? :`
```swift
let foo = isEnable ? "A" : "B"
```
2. 空字典(`empty dictionary `) `[:]`
```swift
let bar: [String: Int] = [:]
```
3. `#selector`語法的無參方法`(_:)`
```swift
let sel = #selector((_:))
```
**推薦:**
```swift
/// 注意使用空格的位置
class TestDatabase: Database {
var data: [String: CGFloat] = ["A": 1.2, "B": 3.2]
}
```
**不推薦:**
```swift
class TestDatabase : Database {
var data :[String:CGFloat] = ["A" : 1.2, "B":3.2]
}
```
### 注釋 (Comments)
* 給方法或屬性添加注釋,使用`option + command + /`來讓Xcode自動生成
* 給關鍵邏輯添加一些局部注釋
* 注釋要保持最新狀態
### 類和結構體 (Classes and Structures)
**用哪個呢?**
要知道結構體(`struct`)是值類型,當事物不具有唯一性時,使用結構體。比如,一個數組`[a, b, c]`,那么另一個數組`[a, b, c]`就跟它是一樣的,他們之間可以互為替換,這時應當使用結構體來表示。
類(`class`)是引用類型,當事物具有唯一性或有明確的生命周期時,使用類。比如,一個電話簿列表,它的每一條記錄都是唯一的,這時就要用類來表示。
以下是一個類的定義:
```swift
class Circle: Shape {
var x: Int
var 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`
* 方法之間保留一個空行
* 有默認的修飾符(如:`internal`)時不用重新添加。同樣的,重載(`override`)方法時,不用重新添加訪問修飾符`access modifier `
* 將功能組織整理到擴展中(`extensions`)
* 隱藏一些不必公開的實現細節,如`_centerString`屬性用`private`來修飾。
#### 使用self (Use of Self)
在Swift中,可以省略`self`來訪問一個對象的屬性或方法。但為了消除使用的歧義,建議使用`self`來訪問其屬性或方法。
#### 計算屬性 (Computed Properties)
為了簡潔性,如果一個計算屬性是只讀(`read-only`)的,那么應省略`get { ... }`語句。`get { ... }`語句只在計算屬性是讀寫(`read-write`)時,才要求使用。
**推薦:**
```swift
var diameter: Double {
return radius * 2
}
```
**不推薦:**
```swift
var diameter: Double {
get {
return radius * 2
}
}
```
#### 使用final標記 (Final)
出于某些原因,你可能不希望一個類被繼承,這時你可以將其標記為`final`來表示它不能被繼承。例如:一個單例,可能就不希望被繼承。
### 函數聲明 (Function Declarations)
將簡短的函數聲明保留在一行中,包括左括號。
```swift
func reticulateSplines(spline: [Double]) -> Bool {
/* code goes here */
}
```
無返回值的函數可以省略`-> Void`返回值
```swift
func foo(arg: Int) {
/* code goes here */
}
```
參數較多的函數可以像`Objective-C`中一樣進行折行處理
```swift
func foo(arg1: Int,
arg2: Double,
arg3: String,
arg4: [Bool],
arg5: () -> Void) {
/* code goes here */
}
```
### 閉包表達式 (Closure Expressions)
當參數列表末尾只有一個閉包參數時,才應使用尾隨閉包(`trailing closure`)語法。
**推薦:**
```swift
// 參數列表尾部只有一個閉包參數
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()
})
```
**不推薦:**
```swift
UIView.animate(withDuration: 1.0, animations: {
self.myView.alpha = 0
})
UIView.animate(withDuration: 1.0, animations: {
self.myView.alpha = 0
}) { finished in
self.myView.removeFromSuperview()
}
```
對于單行的閉包,可以利用隱式返回(`implicit returns`)的特性:
```swift
list.sort { a, b in
a > b
}
```
對于使用閉包的鏈式調用,應當讓代碼更清晰、更易讀。可以借助空格(`spacing`)、換行(`line breaks`)和匿名參數(`anonymous arguments`)等方法來讓代碼更清晰、更易讀,但這都依賴于你的選擇。
```swift
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}
```
### 類型 (Types)
應盡量使用`Swift`的原生類型,當然`Swift`提供了對`Objective-C`類型的橋接方法,你可以使用`Objective-C的所有方法。
**推薦:**
```swift
let width = 120.0 // Double
let widthString = (width as NSNumber).stringValue // String
```
**不推薦:**
```swift
let width: NSNumber = 120.0 // NSNumber
let widthString: NSString = width.stringValue // NSString
```
#### 常量 (Constants)
常量使用關鍵字`let`定義,變量使用關鍵字`var`定義。除非值可變,否則都應使用關鍵字`let`定義。
在一個類型的內部,通過關鍵字`static let`來定義靜態常量,這樣可以更好的組織這些靜態常量。
**推薦:**
```swift
/// 將所有的接口都定義在一個類型內部,方便外部使用
struct API {
static let homeAPI: String = "https://www.example.com/home/"
static let mineAPI: String = "https://www.example.com/mine/"
}
enum Math {
static let e = 2.718281828459045235360287
static let pi = 3.14159265358979323846264
}
let l = 2 * Math.pi * r
```
**不推薦:**
```swift
let homeAPI: String = "https://www.example.com/home/"
let mineAPI: String = "https://www.example.com/mine/"
let e = 2.718281828459045235360287
let pi = 3.14159265358979323846264
let l = 2 * Math.pi * r
```
類內部的靜態方法和屬性,有點類似于全局方法和屬性。但應盡量避免使用全局方法和屬性。有一些例外情況,比如當使用到`runtime`的`objc_getAssociatedObject()`函數時,需要定義個全局的key來作為參數:
```swift
extension UIView {
var foo: Int? {
return objc_getAssociatedObject(self, &_fooKey) as? Int
}
}
private var _fooKey: Void?
```
#### 可選類型 (Optionals)
當使用`?`來定義可選類型時,表明它可以接受為`nil`的值。
當使用`!`來定義可選類型時,表明它可以接受為`nil`的值,但必須保證在使用它時,值不為`nil`。就像`ViewController`中的`view`在`viewDidLoad`被調用時就已經創建完成。
使用可選綁定(`optional binding`)來一次性解包單個或多個可選類型值。
**推薦:**
```swift
var foo: Int?
var bar: Bool?
if let foo = foo, let bar = bar {
// 同時解包foo和bar后才會執行這里
}
```
**不推薦:**
```swift
var foo: Int?
var bar: Bool?
if let foo = foo {
if let bar = bar {
// 同時解包foo和bar后才會執行這里
}
}
```
#### 懶加載 (Lazy Initialization)
使用懶加載(`lazy initialization`)來延遲初始化,這是一個很好的特性。如:
```swift
// 對象不需要進行配置
lazy var foo: SomeBigType = SomeBigType()
// 對象需要進行配置時,使用{ ... }()這種形式
lazy var bar: OtherBigType = { [unowned self] in
let obt = OtherBigType()
obt.delegate = self
return obt
}()
```
**注意:**
> 上面代碼中使用到了`self`,所以需要使用`[unowned self]`來避免產生循環引用(`retain cycle`)
#### 類型推導 (Type Inference)
對于局部變量,盡量使用類型推導來讓代碼更緊湊。而對于成員變量來說,應盡量不要使用類型推導來讓類的定義更清晰。
**推薦:**
```swift
struct Box: Shape {
var width: Int = 10
var height: Int = 10
var foo: [Int] = []
var bar: [String: Int] = [:]
func scale(rate: Int) {
let width = self.width * rate
let height = self.height * rate
self.width = width
self.height = height
}
}
```
**不推薦:**
```swift
struct Box: Shape {
var width = 10
var height = 10
var foo = [Int]()
var bar = [String: Int]()
func scale(rate: CGFloat) {
let width: Int = self.width * rate
let height: Int = self.height * rate
self.width = width
self.height = height
}
}
```
#### 語法糖 (Syntactic Sugar)
利用語法糖,使用更簡短的聲明方式:
**推薦:**
```swift
var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?
```
**不推薦:**
```swift
var deviceModels: Array<String>
var employees: Dictionary<Int, String>
var faxNumber: Optional<Int>
```
### 內存管理 (Memory Management)
可以通過使用`weak` 和 `unowned`來避免循環引用,但也可以直接使用值類型(`struct`, `enum`)來避免循環引用。
通過`guard let`的形式來產生`strongSelf`:
**推薦:**
```swift
resource.request().onComplete { [weak self] response in
guard let strongSelf = self else {
return
}
let model = strongSelf.updateModel(response)
strongSelf.updateUI(model)
}
```
**不推薦:**
```swift
// 當self的釋放先于onComplete回調時,可能引起崩潰
resource.request().onComplete { [unowned self] response in
let model = self.updateModel(response)
self.updateUI(model)
}
```
**不推薦:**
```swift
// 當self的釋放介于updateModel()和updateUI()方法之間時,可能會出現意想不到的情況
resource.request().onComplete { [weak self] response in
let model = self?.updateModel(response)
self?.updateUI(model)
}
```
### 訪問控制 (Access Control)
一般來說,被標記為`private`、`fileprivate`的屬性或方法都應以下劃線(`_`)開頭。
**推薦:**
```swift
private var _isEnabled: Bool
fileprivate var _isClosed: Bool
private func _foo() {
// code goes here
}
fileprivate func _bar() {
// code goes here
}
```
**不推薦:**
```swift
private var isEnabled: Bool
fileprivate var isClosed: Bool
private func foo() {
// code goes here
}
fileprivate func bar() {
// code goes here
}
```
但例外情況是,當標記被修飾為`private(set)`、`fileprivate(set)`時,不需要下劃線(`_`)開頭,因為他們都是可訪問的屬性,只是他們都是只讀屬性而已,如:
```swift
private(set) var isEnabled: Bool
fileprivate(set) var isClosed: Bool
```
一般將訪問控制標記(`access control annotation`)放在聲明的最前面,但例外情況是,當有屬性標記`@IBAction`、`@IBOutlet`、`@discardableResult`、`@objc`時,需要將屬性標記放在最前面。
```swift
private let _message = "Great Scott!"
class TimeMachine {
@IBOutlet private var _lbTitle: UILabel!
@objc private func _foo() -> Bool {
// code goes here
}
}
```
### 控制流 (Control Flow)
優先使用 `for-in` 的方式而不用`while`。
**推薦:**
```swift
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)
}
```
**不推薦:**
```swift
var i = 0
while i < 3 {
print("Hello three times")
i += 1
}
var i = 0
while i < attendeeList.count {
let person = attendeeList[i]
print("\(person) is at position #\(i)")
i += 1
}
```
### 使用Guard語句
通過使用`guard`來避免使用`if`時代碼塊嵌套過深的問題。
**推薦:**
```swift
func check(phone: String?, name: String?, age: Int) -> Bool {
guard let ph = phone, ph.count > 0 else {
return false
}
guard let nm = name, nm.count > 0 else {
return false
}
guard age > 0 else {
return false
}
return true
}
```
**推薦:**
```swift
func check(phone: String?, name: String?, age: Int) -> Bool {
// 把對phone、name、age的判斷放到一個guard里,更簡潔
guard
let ph = phone, ph.count > 0,
let nm = name, nm.count > 0,
age > 0 else {
return false
}
return true
}
```
**不推薦:**
```swift
func check(phone: String?, name: String?, age: Int) -> Bool {
if let ph = phone, ph.count > 0 {
if let nm = name, nm.count > 0 {
if age > 0 {
return true
} else {
return false
}
} else {
return false
}
} else {
return false
}
}
```
### 分號 (Semicolons)
在Swift中不要求必須加分號,一般情況下你不需要使用分號。只有當你希望將多行代碼寫在一行時,才需要加分號來斷句。
### 圓括號 (Parentheses)
一般情況下,在類似`if`條件、`for`循環等控制語句中不需要加圓括號。只有當你在進行數學運算時,希望代碼可讀性更高時才需要適當的添加圓括號。
**推薦:**
```swift
let result = ((x * y) + 2) / h
```
**不推薦:**
```swift
let result = (x * y + 2) / h
```
### 引用
* [swift-style-guide](https://github.com/raywenderlich/swift-style-guide/blob/master/README.markdown)
* [The Swift Programming Language](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/index.html)# 凡普信iOS代碼規范V1.0
---
> 凡普信iOS開發端代碼規范
---
## Objective-C代碼規范
???
<mark>
<br>把布局放在了第一位感覺這個是最重要的,其他的規范感覺大家平時都已經注意了,所以放在了后面 <br>
</mark>
???
### 一、布局規范
#### 1、頭文件引入
按照一定順序引入頭文件
```
#import <系統庫>
#import <第三方>
#import "項目類"
```
#### 2、屬性 和 私有變量
public 和 非public 屬性建議放在相應的地方
```
@interface ClassA ()
@property (nonatomic,strong) NSString *name;
@end
```
私有變量建議命名遵循其中一個,為了規避iOS的命名,特性個人推薦第二種方法命名私有變量
```
NSString *_title;
NSString *title_;
```
#### 3、類內部布局
```
#pragma mark - lifeCycle (這部分寫生命周期方法)
#pragma mark - <UITableViewDelegate> (系統的delegate方法)
#pragma mark - <CustomDelegate> (自定義的delegate方法)
#pragma mark - event response (交互方法)
#pragma mark - private methods (非公共方法)
#pragma mark - view getter(lazy) (主要是View懶加載)
#pragma mark - view setter
#pragma mark - data getter
#pragma mark - data setter
```
這個根據具體類的情況去自己可以增刪
對于private methods 和 event response 等等只是在本類中調用的方法建議以p_開頭,以后修改的時候能了解修改會造成的影響范圍
例如:
```
#pragma mark -private methods
- (void)p_didSelectQuestionItem:(NSDictionary *)questionItem
#pragma mark -event response
- (void)p_searchEventClick:(UIButton *)button
```
### 二、注釋
> 添加必要的注釋
>
* 所有的property 需要給出注釋;
>
* 所有自定義的方法需要給出注釋;
>
* 比較大的代碼塊需要給出注釋;
>
* 所有代碼中出現的阿拉伯數字需要給出注釋;
>
* 程序中出現加密/解密 邏輯的操作地方,需要給出注釋說明過程(無論是系統還是自定義)。
#### 1、每個類頭部有自己的獨白 比如一個viewController是用來做什么的 可以首先寫個注釋說明下 其他的類雷同
```
/**
這是一個用來測試注釋的viewController
注意點:
設計思路:
等等吧 你想說的告白都在這里
*/
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
{
}
- (void)viewDidLoad {
[super viewDidLoad];
}
@end
```
#### 2、單行,多行注釋
單行注釋 //+說明
```
// 初始化默認數據
[self p_setupDefaultData];
```
多行 /* */
```
/*!
XXX的狀態
- XXXType_1: 孩子找媽媽中
- XXXType_1: 孩子找爸爸中
- XXXType_1: 孩子找小朋友中
*/
typedef NS_ENUM(NSUInteger,XXXType) {
XXXType_1,
XXXType_2,
XXXType_3,
};
```
方法注釋
Commond+option+/
```
/**
向某人默認打招呼
@param name 某人
*/
- (void)sayHelloToPeople:(NSString *)name{
}
```
TODO標記
//TODO:XXX
用//TODO去做一些值得注意 或者 自己未完成的標志
```
- (void)sayHelloToPeople:(NSString *)name{
//TODO:向某人打招呼邏輯
}
```
### 三、一些縮進
#### 1、縮進
方法之間保留一行空行,
方法和屬性的格式請按照以下格式書寫:
```
- (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath;
```
```
- (void)viewDidLoad {
[super viewDidLoad];
}
```
```
@property (nonatomic, strong, readonly, nullable) NSIndexPath *previouslyFocusedIndexPath;
```
### 四、常見注意點:
- 盡量避免在程序中直接出現常數,使用超過一次的應以宏定義或枚舉的形式來替代。
- 常數的宏定義應與它實際使用時的類型相一致。如以3.0來定義浮點類型,用3表示整型。常量的命名應當能夠表達出它的用途,并且用大寫字母表示。例如:#definePI 3.1415926
- 刪除多余的空行、注釋、方法以及未被使用的資源文件。
```
UIKIT_EXTERN NSNotificationName const UIKeyboardWillShowNotification;
```
```
UIKIT_EXTERN NSString *const UIKeyboardFrameBeginUserInfoKey
```
```
typedef NS_ENUM(NSInteger, NSWritingDirectionFormatType) {
NSWritingDirectionEmbedding = (0 << 1),
NSWritingDirectionOverride = (1 << 1)
}
```
```
typedef NSString * NSAttributedStringDocumentReadingOptionKey
```
---
---
## Swift 編程規范
> 良好的編程規范有利于項目的維護,同時也能避免因人為的疏忽產生的錯誤。本篇編碼規范主要參考了 [swift-style-guide](https://github.com/raywenderlich/swift-style-guide/blob/master/README.markdown)和[The Swift Programming Language](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/index.html)當中的規范,并綜合了實際開發中總結的經驗。
### 正確性 (Correctness)
力爭讓你的代碼沒有編譯警告(`warning`)。這個規則下延伸出了許多決定,如:使用`#selector`方式,而不是直接使用字符串。
### 命名 (Naming)
描述性和一致性的命名使得代碼更易讀、更易懂。一些規則如下:
* 追求調用方的清晰性
* 優先使用更清晰的命名,而不是更簡潔的
* 使用駝峰樣式
* 類型、協議名首字母大寫,其他的都首字母小寫
* 包含所有需要的單詞,省略不必要的
* 使用基于角色的命名,而不是基于類型的
* 工廠方法使用`make`開頭
* 對方法的命名
* 動詞方法以`-ed`結尾,對于不可變的(`non-mutating`)動詞方法用`-ing`結尾
* 布爾類型(`boolean`)應該以`is`開頭
* 用于描述事物的協議(`protocols`)名稱,用名詞命名
* 用于描述能力的協議(`protocols`)名稱,應以`-able` 或 `-ible`結尾
* 不要用生僻的單詞
* 通常不要用縮寫
* 選用好的參數名來起到描述的作用
#### 類前綴 (Class Prefixes)
Swift中的類型自動使用了其所在的模塊(`module`)作為命名空間(`namespace`),所以你不必給類型加前綴。如果來自不同模塊的類型名子沖突,可以顯示的使用模塊名作為調用前綴來避免沖突。
```swift
import SomeModule
import OtherModule
let someUsefulClass = SomeModule.UsefulClass()
let otherUsefulClass = OtherModule.UsefulClass()
```
#### 代理 (Delegates)
當定義一個代理方法時,第一個匿名參數應該是代理的源對象。(`UIKit`中有許多這樣的的例子)
**推薦:**
```swift
func namePickerView(_ namePickerView: NamePickerView, didSelectName name: String)
func namePickerViewShouldReload(_ namePickerView: NamePickerView) -> Bool
```
**不推薦:**
```swift
/// `namePicker`應該是匿名的
func didSelectName(namePicker: NamePickerViewController, name: String)
/// 至少應包含`_ namePickerView: NamePickerView`參數,來作為代理的源對象
func namePickerShouldReload() -> Bool
```
#### 使用可類型推導的上下文 (Use Type Inferred Context)
利用好編譯器的類型推導特性,來寫出簡短、清晰的代碼。
**推薦:**
```swift
let selector = #selector(viewDidLoad)
view.backgroundColor = .red
let toView = context.view(forKey: .to)
let view = UIView(frame: .zero)
```
**不推薦:**
```swift
// 以下幾種寫法,都沒有用到編譯器的類型推導特性,寫出來的代碼較冗余
let selector = #selector(ViewController.viewDidLoad)
view.backgroundColor = UIColor.red
let toView = context.view(forKey: UITransitionContextViewKey.to)
let view = UIView(frame: CGRect.zero)
```
#### 泛型 (Generics)
泛型參數(`generic type parameters`)應當使用具有描述性的駝峰樣式來命名。當泛型參數不具有明確的關系或角色時,可使用一個大寫的字母表示即可。如:`T`,`U`,`V`
#### 使用的語言 (Language)
應使用美式英語的拼寫方式以匹配Apple的API,應盡量保持命名的可讀性,不應該用多含義且有相反或者混淆意思的單詞。
**推薦:**
```swift
let color = "red"
```
**不推薦:**
```swift
let colour = "red"
```
### 代碼組織 (Code Organization)
盡可能的使用擴展(`extensions`)來解耦你的代碼,將代碼劃分到不同的擴展模塊中,每個擴展應以`// MARK: -`開頭,來更好的區分擴展。
#### 協議的遵守 (Protocol Conformance)
具體來講,當讓一個`Model`遵守某個協議時,推薦添加一個獨立的`Model`擴展(`extensions`)來遵守該協議。這樣使得相關的協議方法能組織在一起。
**推薦:**
```swift
class MyViewController: UIViewController {
// class stuff here
}
// MARK: - UITableViewDataSource
extension MyViewController: UITableViewDataSource {
// table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewController: UIScrollViewDelegate {
// scroll view delegate methods
}
```
**不推薦:**
```swift
class MyViewController: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
// all methods
}
```
對于`UIKit`的視圖控制器(`view controllers`),可以考慮將生命周期(`lifecycle`)相關、自定義訪問器(`custom accessors`)、`IBAction`獨立不同的到類擴展中。
#### 無用的代碼 (Unused Code)
無用的代碼包括Xcode產生的模板代碼、占位的注釋等、方法的默認實現僅僅是調用`super`等,這些都應當移除掉。
**推薦:**
```swift
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Database.contacts.count
}
```
**不推薦:**
```swift
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return Database.contacts.count
}
```
#### 減小引入 (Minimal Imports)
保存最小的引入(`imports`)。例如, 當只使用`Foundation`時,不要引入`UIKit`。
### 空格 (Spacing)
* 代碼折行使用4個空格(`spaces`)
* 方法的大括號和其他大括號(`if`/`else`/`switch`/`while`等),其左括號必須要和語句在同一行,并且右括號要換行;
* 變量類型和冒號(:)之間保留一個空格;
* 返回值標記`->`兩側各保留一個空格;
**推薦:**
```swift
if user.isHappy {
// Do something
} else {
// Do something else
}
```
**不推薦:**
```swift
if user.isHappy
{
// Do something
}
else {
// Do something else
}
```
* 各個方法之間必須有一個空行,這使得代碼視覺上更清晰。
* 方法的實現中,應當適當的添加空行來劃分功能。過多的空行意味著你應該拆分這些功能到不同的方法中,通過這樣來避免一個巨大的方法。
* 通常冒號(Colons)的左邊應當沒有空格,而在右邊有一個空格。
例外:
1. 三目運算符(`ternary operator`) `? :`
```swift
let foo = isEnable ? "A" : "B"
```
2. 空字典(`empty dictionary `) `[:]`
```swift
let bar: [String: Int] = [:]
```
3. `#selector`語法的無參方法`(_:)`
```swift
let sel = #selector((_:))
```
**推薦:**
```swift
/// 注意使用空格的位置
class TestDatabase: Database {
var data: [String: CGFloat] = ["A": 1.2, "B": 3.2]
}
```
**不推薦:**
```swift
class TestDatabase : Database {
var data :[String:CGFloat] = ["A" : 1.2, "B":3.2]
}
```
### 注釋 (Comments)
* 給方法或屬性添加注釋,使用`option + command + /`來讓Xcode自動生成
* 給關鍵邏輯添加一些局部注釋
* 注釋要保持最新狀態
### 類和結構體 (Classes and Structures)
**用哪個呢?**
要知道結構體(`struct`)是值類型,當事物不具有唯一性時,使用結構體。比如,一個數組`[a, b, c]`,那么另一個數組`[a, b, c]`就跟它是一樣的,他們之間可以互為替換,這時應當使用結構體來表示。
類(`class`)是引用類型,當事物具有唯一性或有明確的生命周期時,使用類。比如,一個電話簿列表,它的每一條記錄都是唯一的,這時就要用類來表示。
以下是一個類的定義:
```swift
class Circle: Shape {
var x: Int
var 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`
* 方法之間保留一個空行
* 有默認的修飾符(如:`internal`)時不用重新添加。同樣的,重載(`override`)方法時,不用重新添加訪問修飾符`access modifier `
* 將功能組織整理到擴展中(`extensions`)
* 隱藏一些不必公開的實現細節,如`_centerString`屬性用`private`來修飾。
#### 使用self (Use of Self)
在Swift中,可以省略`self`來訪問一個對象的屬性或方法。但為了消除使用的歧義,建議使用`self`來訪問其屬性或方法。
#### 計算屬性 (Computed Properties)
為了簡潔性,如果一個計算屬性是只讀(`read-only`)的,那么應省略`get { ... }`語句。`get { ... }`語句只在計算屬性是讀寫(`read-write`)時,才要求使用。
**推薦:**
```swift
var diameter: Double {
return radius * 2
}
```
**不推薦:**
```swift
var diameter: Double {
get {
return radius * 2
}
}
```
#### 使用final標記 (Final)
出于某些原因,你可能不希望一個類被繼承,這時你可以將其標記為`final`來表示它不能被繼承。例如:一個單例,可能就不希望被繼承。
### 函數聲明 (Function Declarations)
將簡短的函數聲明保留在一行中,包括左括號。
```swift
func reticulateSplines(spline: [Double]) -> Bool {
/* code goes here */
}
```
無返回值的函數可以省略`-> Void`返回值
```swift
func foo(arg: Int) {
/* code goes here */
}
```
參數較多的函數可以像`Objective-C`中一樣進行折行處理
```swift
func foo(arg1: Int,
arg2: Double,
arg3: String,
arg4: [Bool],
arg5: () -> Void) {
/* code goes here */
}
```
### 閉包表達式 (Closure Expressions)
當參數列表末尾只有一個閉包參數時,才應使用尾隨閉包(`trailing closure`)語法。
**推薦:**
```swift
// 參數列表尾部只有一個閉包參數
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()
})
```
**不推薦:**
```swift
UIView.animate(withDuration: 1.0, animations: {
self.myView.alpha = 0
})
UIView.animate(withDuration: 1.0, animations: {
self.myView.alpha = 0
}) { finished in
self.myView.removeFromSuperview()
}
```
對于單行的閉包,可以利用隱式返回(`implicit returns`)的特性:
```swift
list.sort { a, b in
a > b
}
```
對于使用閉包的鏈式調用,應當讓代碼更清晰、更易讀。可以借助空格(`spacing`)、換行(`line breaks`)和匿名參數(`anonymous arguments`)等方法來讓代碼更清晰、更易讀,但這都依賴于你的選擇。
```swift
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}
```
### 類型 (Types)
應盡量使用`Swift`的原生類型,當然`Swift`提供了對`Objective-C`類型的橋接方法,你可以使用`Objective-C的所有方法。
**推薦:**
```swift
let width = 120.0 // Double
let widthString = (width as NSNumber).stringValue // String
```
**不推薦:**
```swift
let width: NSNumber = 120.0 // NSNumber
let widthString: NSString = width.stringValue // NSString
```
#### 常量 (Constants)
常量使用關鍵字`let`定義,變量使用關鍵字`var`定義。除非值可變,否則都應使用關鍵字`let`定義。
在一個類型的內部,通過關鍵字`static let`來定義靜態常量,這樣可以更好的組織這些靜態常量。
**推薦:**
```swift
/// 將所有的接口都定義在一個類型內部,方便外部使用
struct API {
static let homeAPI: String = "https://www.example.com/home/"
static let mineAPI: String = "https://www.example.com/mine/"
}
enum Math {
static let e = 2.718281828459045235360287
static let pi = 3.14159265358979323846264
}
let l = 2 * Math.pi * r
```
**不推薦:**
```swift
let homeAPI: String = "https://www.example.com/home/"
let mineAPI: String = "https://www.example.com/mine/"
let e = 2.718281828459045235360287
let pi = 3.14159265358979323846264
let l = 2 * Math.pi * r
```
類內部的靜態方法和屬性,有點類似于全局方法和屬性。但應盡量避免使用全局方法和屬性。有一些例外情況,比如當使用到`runtime`的`objc_getAssociatedObject()`函數時,需要定義個全局的key來作為參數:
```swift
extension UIView {
var foo: Int? {
return objc_getAssociatedObject(self, &_fooKey) as? Int
}
}
private var _fooKey: Void?
```
#### 可選類型 (Optionals)
當使用`?`來定義可選類型時,表明它可以接受為`nil`的值。
當使用`!`來定義可選類型時,表明它可以接受為`nil`的值,但必須保證在使用它時,值不為`nil`。就像`ViewController`中的`view`在`viewDidLoad`被調用時就已經創建完成。
使用可選綁定(`optional binding`)來一次性解包單個或多個可選類型值。
**推薦:**
```swift
var foo: Int?
var bar: Bool?
if let foo = foo, let bar = bar {
// 同時解包foo和bar后才會執行這里
}
```
**不推薦:**
```swift
var foo: Int?
var bar: Bool?
if let foo = foo {
if let bar = bar {
// 同時解包foo和bar后才會執行這里
}
}
```
#### 懶加載 (Lazy Initialization)
使用懶加載(`lazy initialization`)來延遲初始化,這是一個很好的特性。如:
```swift
// 對象不需要進行配置
lazy var foo: SomeBigType = SomeBigType()
// 對象需要進行配置時,使用{ ... }()這種形式
lazy var bar: OtherBigType = { [unowned self] in
let obt = OtherBigType()
obt.delegate = self
return obt
}()
```
**注意:**
> 上面代碼中使用到了`self`,所以需要使用`[unowned self]`來避免產生循環引用(`retain cycle`)
#### 類型推導 (Type Inference)
對于局部變量,盡量使用類型推導來讓代碼更緊湊。而對于成員變量來說,應盡量不要使用類型推導來讓類的定義更清晰。
**推薦:**
```swift
struct Box: Shape {
var width: Int = 10
var height: Int = 10
var foo: [Int] = []
var bar: [String: Int] = [:]
func scale(rate: Int) {
let width = self.width * rate
let height = self.height * rate
self.width = width
self.height = height
}
}
```
**不推薦:**
```swift
struct Box: Shape {
var width = 10
var height = 10
var foo = [Int]()
var bar = [String: Int]()
func scale(rate: CGFloat) {
let width: Int = self.width * rate
let height: Int = self.height * rate
self.width = width
self.height = height
}
}
```
#### 語法糖 (Syntactic Sugar)
利用語法糖,使用更簡短的聲明方式:
**推薦:**
```swift
var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?
```
**不推薦:**
```swift
var deviceModels: Array<String>
var employees: Dictionary<Int, String>
var faxNumber: Optional<Int>
```
### 內存管理 (Memory Management)
可以通過使用`weak` 和 `unowned`來避免循環引用,但也可以直接使用值類型(`struct`, `enum`)來避免循環引用。
通過`guard let`的形式來產生`strongSelf`:
**推薦:**
```swift
resource.request().onComplete { [weak self] response in
guard let strongSelf = self else {
return
}
let model = strongSelf.updateModel(response)
strongSelf.updateUI(model)
}
```
**不推薦:**
```swift
// 當self的釋放先于onComplete回調時,可能引起崩潰
resource.request().onComplete { [unowned self] response in
let model = self.updateModel(response)
self.updateUI(model)
}
```
**不推薦:**
```swift
// 當self的釋放介于updateModel()和updateUI()方法之間時,可能會出現意想不到的情況
resource.request().onComplete { [weak self] response in
let model = self?.updateModel(response)
self?.updateUI(model)
}
```
### 訪問控制 (Access Control)
一般來說,被標記為`private`、`fileprivate`的屬性或方法都應以下劃線(`_`)開頭。
**推薦:**
```swift
private var _isEnabled: Bool
fileprivate var _isClosed: Bool
private func _foo() {
// code goes here
}
fileprivate func _bar() {
// code goes here
}
```
**不推薦:**
```swift
private var isEnabled: Bool
fileprivate var isClosed: Bool
private func foo() {
// code goes here
}
fileprivate func bar() {
// code goes here
}
```
但例外情況是,當標記被修飾為`private(set)`、`fileprivate(set)`時,不需要下劃線(`_`)開頭,因為他們都是可訪問的屬性,只是他們都是只讀屬性而已,如:
```swift
private(set) var isEnabled: Bool
fileprivate(set) var isClosed: Bool
```
一般將訪問控制標記(`access control annotation`)放在聲明的最前面,但例外情況是,當有屬性標記`@IBAction`、`@IBOutlet`、`@discardableResult`、`@objc`時,需要將屬性標記放在最前面。
```swift
private let _message = "Great Scott!"
class TimeMachine {
@IBOutlet private var _lbTitle: UILabel!
@objc private func _foo() -> Bool {
// code goes here
}
}
```
### 控制流 (Control Flow)
優先使用 `for-in` 的方式而不用`while`。
**推薦:**
```swift
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)
}
```
**不推薦:**
```swift
var i = 0
while i < 3 {
print("Hello three times")
i += 1
}
var i = 0
while i < attendeeList.count {
let person = attendeeList[i]
print("\(person) is at position #\(i)")
i += 1
}
```
### 使用Guard語句
通過使用`guard`來避免使用`if`時代碼塊嵌套過深的問題。
**推薦:**
```swift
func check(phone: String?, name: String?, age: Int) -> Bool {
guard let ph = phone, ph.count > 0 else {
return false
}
guard let nm = name, nm.count > 0 else {
return false
}
guard age > 0 else {
return false
}
return true
}
```
**推薦:**
```swift
func check(phone: String?, name: String?, age: Int) -> Bool {
// 把對phone、name、age的判斷放到一個guard里,更簡潔
guard
let ph = phone, ph.count > 0,
let nm = name, nm.count > 0,
age > 0 else {
return false
}
return true
}
```
**不推薦:**
```swift
func check(phone: String?, name: String?, age: Int) -> Bool {
if let ph = phone, ph.count > 0 {
if let nm = name, nm.count > 0 {
if age > 0 {
return true
} else {
return false
}
} else {
return false
}
} else {
return false
}
}
```
### 分號 (Semicolons)
在Swift中不要求必須加分號,一般情況下你不需要使用分號。只有當你希望將多行代碼寫在一行時,才需要加分號來斷句。
### 圓括號 (Parentheses)
一般情況下,在類似`if`條件、`for`循環等控制語句中不需要加圓括號。只有當你在進行數學運算時,希望代碼可讀性更高時才需要適當的添加圓括號。
**推薦:**
```swift
let result = ((x * y) + 2) / h
```
**不推薦:**
```swift
let result = (x * y + 2) / h
```
### 引用
* [swift-style-guide](https://github.com/raywenderlich/swift-style-guide/blob/master/README.markdown)
* [The Swift Programming Language](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/index.html)
- 說明
- Python編程規范
- Python風格規范
- Python語言規范
- Java編程規范
- 一、命名約定
- 二、常量定義
- 三、格式約定
- 四、OOP約定
- 五、集合處理
- 六、并發控制
- 七、控制語句
- 八、注釋約定
- 九、異常日志
- 十、日志約定
- Android開發規范
- 前端開發規范
- HTML
- JavaScript
- CSS
- MySQL約定
- 一、基本規范
- 二、庫表設計規范
- 三、字段設計規范
- 四、索引規范
- 五、SQL設計規范
- 六、業務字段命名規范
- 開發安全約定
- 一、代碼安全
- 二、移動開發安全
- 三、服務器安全
- 四、安全意識
- 版本管理
- Git使用規范
- 技術實踐及可視化
- 一、Code Review
- 二、單元測試
- 三、自動化測試
- 四、技術債
- 五、CI
- IOS開發規范