SWIFT 5.0 开发规范

SWIFT 5.0 开发规范

一:格式规范

1.0 二元运算符(+, ==, 或->)的前后都需要添加空格

let value = 1 + 2
                    
if value == 1 {
    /* ... */
}

1.1 switch case中如果有内容 不用加 break 没有则需要

// 推荐
switch i {
case .a:
    print("a")

case .b:
  break
    
default:
    default
}

1.3 代码结尾不要使用分号;

// 推荐
print("Hello World")
// 不推荐
print("Hello World");

1.4 左大括号不要另起一行

// 推荐
// 1. Class Define
class TestClass {
    /* ... */
}

// 2. if
if value == 1 {
    /* ... */
}

// 3. if else
if value == 1 {
    /* ... */
} else {
    /* ... */
}

// 4. while
while isTrue {
    /* ... */
}

// 5. guard
guard let value = value else  {
    /* ... */
}
// 不推荐
// 1. Class Define
class TestClass 
{
    /* ... */
}

// 2. if
if value == 1
{
    /* ... */
}

// 3. if else
if value == 1
{
    /* ... */
}
else
{
    /* ... */
}

// 4. while
while isTrue 
{
    /* ... */
}

// 5. guard
guard let value = value else 
{
    /* ... */
}

1.5 判断语句不用括号

// 推荐
if value == 1 {
    /* ... */
}

if value == 1 && string == "test" {
    /* ... */
}
// 不推荐
if (value == 1) {
    /* ... */
}

if ((value == 1) && (string == "test")) {
    /* ... */
}

1.6 善用类型推导, 不写多余代码

// 推荐
func set(color: UIColor) {
    /* ... */
}

set(color: .black)
// 不推荐
func set(color: UIColor) {
    /* ... */
}

set(color: UIColor.black)

1.7 添加有必要的注释,尽可能使用Xcode注释快捷键(⌘⌥/)

// 推荐

/// <#Description#>
///
/// - Parameter test: <#test description#>
/// - Returns: <#return value description#>
func test(string: String?) -> String? {
    /* ... */
}
// 不推荐

/// <#Description#>
func test(string: String?) -> String? {
    /* ... */
}

1.8 使用// MARK: -,按功能和协议 / 代理分组 和 使用 /// 来添加属性注释

/// MARK顺序没有强制要求,但System API & Public API一般分别放在第一块和第二块。

// MARK: - Public

// MARK: - Request

// MARK: - Action

// MARK: - Private

// MARK: - xxxDelegate

二:命名规范

2.0 建议不要使用前缀, 善用命名空间.

// 推荐
HomeViewController
Bundle
// 不推荐
NEHomeViewController
NSBundle

2.1 不要缩写、简写、单个字母来命名

// 推荐
let frame = view.frame
let image = imageView.image
let backgroundColor = view.backgroundColor 
// 不推荐
let f = view.frame
let img = imageView.image
let bgColor = view.backgroundColor 

2.2 如非必要, 不要声明全局常量/变量/函数, 应该根据类型适当归类包装, 合理利用命名空间.

// 推荐
enum Main {
    static let color = UIColor(red: 0.1, green: 0.2, blue: 0.3, alpha: 1.0)
    static let count = 13
    static func font(_ size: CGFloat) -> UIFont {
        return UIFont(name: "xxx", size: size) ?? .systemFont(ofSize: size)
    }
}

// 不推荐
let mainColor = UIColor(red: 0.1, green: 0.2, blue: 0.3, alpha: 1.0)
let mainCount = 13
func mainFont(_ size: CGFloat) -> UIFont {
    return UIFont(name: "xxx", size: size) ?? UIFont.systemFont(ofSize: size)
}

2.3 变量命名 使用小驼峰,首字母小写

// 变量命名应该能推断出该变量类型,如果不能推断,则需要以变量类型结尾
// 推荐
class TestClass: class {
    // UIKit的子类,后缀最好加上类型信息
    let coverImageView: UIImageView
    @IBOutlet weak var usernameTextField: UITextField!

    // 作为属性名的firstName,明显是字符串类型,所以不用在命名里不用包含String
    let firstName: String

    // UIViewContrller以ViewController结尾
    let fromViewController: UIViewController

    // 集合类型以复数形式命名
    var datas: [Data] = []
    var items: [Item] = []
}
// 不推荐
class TestClass: class {
    // image不是UIImageView类型
    let coverImage: UIImageView
    // or cover不能表明其是UIImageView类型
    var cover: UIImageView

    // String后缀多余
    let firstNameString: String

    // UIViewContrller不要缩写
    let fromVC: UIViewController
    
    // 集合类型多余后缀和描述
    var dataList: [Data] = []
    var itemArray: [Item] = []
}

2.4 类型命名:使用大驼峰表示法,首字母大写

2.5 省略所有的冗余的外部参数标签

// 推荐
func min(_ number1: Int, _ number2: Int) {
    /* ... */
}

min(1, 2)
// 不推荐
func min(number1: Int, number2: Int) {
    /* ... */
}

min(number1: 1, number2: 2)

2.6 Bool类型命名:用is为前缀

// 推荐
var isString: Bool = true

2.7 枚举定义尽量简写,不要包括类型前缀

// 推荐
public enum UITableViewRowAnimation: Int {
    case fade

    case right // slide in from right (or out to right)

    case left

    case top

    case bottom

    case none // available in iOS 3.0

    case middle // available in iOS 3.2.  attempts to keep cell centered in the space it will/did occupy

    case automatic // available in iOS 5.0.  chooses an appropriate animation style for you
}

三:语法规范

3.0单例书写

class TestManager: NSObject {
    static let `default` = TestManager()
}

3.1 空判断

// 推荐 xx.isEmpty
if string.isEmpty {
    /* ... */
}
// 不推荐 xx.count == 0

if string.count == 0 {
    /* ... */
}

3.2 在逃逸Closures中使用self时避免循环引用

// 不推荐
request(.list) { [weak self] (result: Result<[Model]>) in
    self?.items = self?.result.value
    self?.tableView.reloadData()
}

// 推荐
request(.list) { [weak self] (result: Result<[Model]>) in
    guard let self = self else { return }

    self.items = self.result.value
    self.tableView.reloadData()
}

3.3 使用委托和协议时,避免循环引用,定义属性的时候使用weak修饰

public weak var dataSource: UITableViewDataSource?

public weak var delegate: UITableViewDelegate?

3.4 Golden Path,最短路径原则

// 推荐
func test(_ number1: Int?, _ number2: Int?, _ number3: Int?) {
    guard
        let number1 = number1, 
        number2 = number2, 
        number3 = number3 else { 
        fatalError("impossible") 
    }
    /* ... */
}

func login(with username: String?, password: String?) throws -> LoginError {
    guard let username = username else { 
        throw .noUsername 
    }
    guard let password = password else { 
        throw .noPassword
    }

    /* login code */
}
/// 不推荐 
func test(_ number1: Int?, _ number2: Int?, _ number3: Int?) {
    if let number1 = number1 {
        if let number2 = number2 {
            if let number3 = number3 {
                /* ... */
            } else {
                fatalError("impossible")
            }
        } else {
            fatalError("impossible")
        }
    } else {
        fatalError("impossible")
    }
}

func login(with username: String?, password: String?) throws -> LoginError {
    if let username = username {
      if let password = password {
          /* login code */
      } else {
          throw .noPassword
      }
    } else {
        throw .noUsername
    }
}

3.5 如调用者可以不使用方法的返回值,则需要使用@discardableResult标明

@discardableResult
func print(message: String) -> String {
    let output = "Output : \(message)"
    print(output)
    return output
}

3.6 高阶函数推荐最简化语法

// 推荐 
array.sort(by: <)

array.sort { $0.age < $1.age }

array.sort { (l, r) -> Bool in
    l < r
}

// 不推荐 
array.sort { (l, r) -> Bool in
    return l < r
}

3.7 协议 当实现protocol时,如果确定protocol的实现不会被重写,建议用extension将protocol实现分离

// 推荐
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
}

// 不推荐
class MyViewController: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
  // all methods
}

3.8 常量和变量可以不指定数据类型

// 推荐
let value = 1 

let text = "xxxx"

// 不推荐
let value: Int = 1 

let text: String = "xxxx"

3.9 数组和字典变量定义,定义时需要标明泛型类型,并使用更简洁的语法.

// 推荐
var names: [String] = []
var lookup: [String: Int] = [:]

// 不推荐
var names = [String]()
var names: Array = [String]() / 不够简洁

var lookup = [String: Int]()
var lookup: Dictionary =Dictionary() // 不够简洁

3.10 在非必要情况下 不要使用! 强制解包

// 推荐
// 使用if let as?判断
if let text = text as? String {
    /* ... */
}

// 使用if let try 或者 try?
if let test = try aTryFuncton() {
    /* ... */
}

3.10 多个可选类型拆包取值时,将多个if let合并, 除非特殊逻辑需要.

// 推荐
var subview: UIView?
var volume: Double?

if let subview = subview, let volume = volume {
    /* ... */
}

// 不推荐
var optionalSubview: UIView?
var volume: Double?

if let unwrappedSubview = optionalSubview {
    if let realVolume = volume {
        /* ... */
    }
}

3.11 可选类型取值

// 推荐
if let optionalValue = optionalValue {
    /* ... */
}

// 不推荐
if  optionalValue != nil {
    let value = optionalValue!
    /* ... */
}

3.12 非必要情况下 不要都使用 var 使用 let

// 推荐
let string = "a"

// 不推荐
var string = "b"

3.13 尽量使用 懒加载

// 推荐
lazy var testView:UIView = {
    let view = UIView()
    return view
}()
// 不推荐
var testView = UIView()

你可能感兴趣的:(SWIFT 5.0 开发规范)