Swift使用规范
Posted 崔小花o
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift使用规范相关的知识,希望对你有一定的参考价值。
一. 格式规范
1.1 使用4个空格进行缩进
推荐
if value == 1
print("")
1.2 二元运算符(+, ==, 或->)的前后都需要添加空格
推荐
let value = 1 + 2
if value == 1
/* ... */
func test(with value: TestClass) -> returnValue
/* ... */
1.3 一般情况下,在逗号和冒号后面加一个空格
推荐
let array = [1, 2, 3, 4, 5]
let dic: [String: Any] = [:]
不推荐
let array = [1,2,3,4,5]
let dic : [String :Any] = [:]
1.4 switch
每个case
结尾留一行空行, 最后一行不留. if
同理.
推荐
switch i
case .a:
print("a")
case .b:
print("b")
default:
default
if isTrue
/* ... 结尾空行 */
else if isFlase
/* ... */
else
/* ... 最后一行不需要空行 */
不推荐
switch i
case .a:
print("a")
case .b:
print("b")
default:
default
if isTrue
/* ... */
else if isFlase
/* ... */
else
/* ... */
1.5 代码结尾不要使用分号;
推荐
print("Hello World")
不推荐
print("Hello World");
1.6 左大括号不要另起一行
推荐
// 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.7 判断语句不用括号
推荐
if value == 1
/* ... */
if value == 1 && string == "test"
/* ... */
不推荐
if (value == 1)
/* ... */
if ((value == 1) && (string == "test"))
/* ... */
1.8 不建议使用self.
,除非方法参数与属性同名或其他必要情况
推荐
func setup()
label = UILabel()
不推荐
func setup()
self.label = UILabel()
1.9 善用类型推导, 不写多余代码
推荐
func set(color: UIColor)
/* ... */
set(color: .black)
不推荐
func set(color: UIColor)
/* ... */
set(color: UIColor.black)
1.10 添加有必要的注释,尽可能使用Xcode注释快捷键(⌘⌥/)
推荐
/// <#Description#>
///
/// - Parameter test: <#test description#>
/// - Returns: <#return value description#>
func test(string: String?) -> String?
/* ... */
不推荐
/// <#Description#>
func test(string: String?) -> String?
/* ... */
1.11 注释符//
后加空格,如果//
跟在代码后面,前面也加一个空格
推荐
// 注释
let aString = "xxx" // 注释
1.12 使用// MARK: -
,按功能和协议 / 代理分组
/// MARK顺序没有强制要求,但System API & Public API一般分别放在第一块和第二块。
// MARK: - Public
// MARK: - Request
// MARK: - Action
// MARK: - Private
// MARK: - xxxDelegate
1.13 对外接口不兼容时,使用@available(ios x.0, *)
标明接口适配起始系统版本号
@available(iOS x.0, *)
class MyClass
/* ... */
@available(iOS x.0, *)
func myFunction()
/* ... */
1.14 方法间合理换行
推荐
extension XXX
// 扩展开始 增加一个换行
func xxxx1()
/* ... */
// 方法之间 增加一个换行
func xxxx2()
/* ... */
// 结尾不要有多余换行
二. 命名规范
2.1 建议不要使用前缀, 善用命名空间.
推荐
HomeViewController
Bundle
不推荐
NEHomeViewController
NSBundle
2.2 不要缩写、简写、单个字母来命名
推荐
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.3 如非必要, 不要声明全局常量/变量/函数, 应该根据类型适当归类包装, 合理利用命名空间.
推荐
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.4 变量命名
-
使用小驼峰,首字母小写
-
变量命名应该能推断出该变量类型,如果不能推断,则需要以变量类型结尾
推荐
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.5 类型命名:使用大驼峰表示法,首字母大写
2.6 方法命名:使用参数标签让方法语义更清楚, 参数标签和参数需要表达正确的语义(Public接口及基础组件必须遵循) (from Swift API Design Guidelines)
2.6.1 省略所有的冗余的外部参数标签
推荐
func min(_ number1: Int, _ number2: Int)
/* ... */
min(1, 2)
不推荐
func min(number1: Int, number2: Int)
/* ... */
min(number1: 1, number2: 2)
2.6.2 进行安全值类型转换的构造方法可以省略参数标签,非安全类型转换则需要添加参数标签以表示类型转换方法
推荐
extension UInt32
/// 安全值类型转换,16位转32位,可省略参数标签
init(_ value: Int16)
/// 非安全类型转换,64位转32位,不可省略参数标签
/// 截断显示
init(truncating source: UInt64)
/// 非安全类型转换,64位转32位,不可省略参数标签
/// 显示最接近的近似值
init(saturating valueToApproximate: UInt64)
2.6.3 当第一个参数构成整个语句的介词时(如,at, by, for, in, to, with 等),为第一个参数添加介词参数标签
推荐
// 添加介词标签having
func removeBoxes(having length: Int)
/* ... */
let length = 23
x.removeBoxes(having: length)
例外情况是,当后面所有参数构成独立短语时,则介词提前。
推荐
// 介词To提前
a.moveTo(x: b, y: c)
// 介词From提前
a.fadeFrom(red: b, green: c, blue: d)
不推荐
a.move(toX: b, y: c)
a.fade(fromRed: b, green: c, blue: d)
2.6.4 当第一个参数构成整个语句一部分时,省略第一个参数标签,否则需要添加第一个参数标签.
推荐
// 参数构成语句一部分,省略第一个参数标签
view.addSubview(tempView)
// 参数不构成语句一部分,不省略第一个参数标签
dismiss(animated: false)
2.6.5 其余情况下,给除第一个参数外的参数都添加标签
2.7 方法命名:不要使用冗余的单词,特别是与参数及参数标签重复
推荐
func remove(_ member: Element) -> Element?
不推荐
func removeElement(_ member: Element) -> Element?
2.8 命名出现缩写词,缩写词要么全部大写,要么全部小写,以首字母大小写为准
推荐
let urlRouterString = "https://xxxxx"
let htmlString = "xxxx"
class HTMLModel
/* ... */
struct URLRouter
/* ... */
不推荐
let uRLRouterString = "https://xxxxx"
let hTMLString = "xxxx"
class HtmlModel
/* ... */
struct UrlRouter
/* ... */
2.9 Bool类型命名:用is
为前缀
推荐
var isString: Bool = true
2.10 枚举定义尽量简写,不要包括类型前缀
推荐
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
2.11 协议命名 (from Swift API Design Guidelines)
2.11.1 如果协议描述的是协议做的事应该命名为名词(eg. Collection
)
推荐
protocol TableViewSectionProvider
func rowHeight(at row: Int) -> CGFloat
var numberOfRows: Int get
/* ... */
2.11.2 如果协议描述的是能力,需添加后缀able或 ing (eg. Equatable、 ProgressReporting)
推荐
protocol Loggable
func logCurrentState()
/* ... */
protocol Equatable
func ==(lhs: Self, rhs: Self) -> Bool
/* ... */
2.11.3 如果已经定义类,需要给类定义相关协议,则添加Protocol
后缀
推荐
protocol InputTextViewProtocol
func sendTrackingEvent()
func inputText() -> String
/* ... */
2.11.4 如果已经定义类,需要给类定义相关委托协议,则添加Delegate
后缀
推荐
public protocol UITabBarControllerDelegate: NSObjectProtocol
@available(iOS 3.0, *)
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool
三. 语法规范
3.1 多使用let
,少使用var
3.2 少用!
去强制解包
3.3 可选类型拆包取值时,使用if let
判断
推荐
if let optionalValue = optionalValue
/* ... */
杜绝
if optionalValue != nil
let value = optionalValue!
/* ... */
3.4 多个可选类型拆包取值时,将多个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.5 不要使用 as! 或 try!
推荐
// 使用if let as?判断
if let text = text as? String
/* ... */
// 使用if let try 或者 try?
if let test = try aTryFuncton()
/* ... */
3.6 数组和字典变量定义,定义时需要标明泛型类型,并使用更简洁的语法.
推荐
var names: [String] = []
var lookup: [String: Int] = [:]
不推荐
var names = [String]()
var names: Array<String> = [String]() / 不够简洁
var lookup = [String: Int]()
var lookup: Dictionary<String, Int> =Dictionary<String, Int>() // 不够简洁
3.7 数组访问尽可能使用 .first 或 .last, 推荐使用 for item in items
或 items.forEach
而不是 for i in 0...X
推荐
items.first
items.last
for item in items
/* ... */
items.forEach
/* ... */
不推荐
items[0]
items[items.count - 1]
for i in 0 ..< items.count
let item = items[i]
/* ... */
3.8 如果变量能够推断出类型,则不建议声明变量时指明类型
推荐
let value = 1
let text = "xxxx"
不推荐
let value: Int = 1
let text: String = "xxxx"
3.9 判断相等
3.9.1 使用==
和!=
判断内容上是否一致
推荐
// String类型没有-isEqualToString方法,用==判断是否相等
let str1 = "netease"
let str2 = "netease"
if str1 == str2
// is true
/* ... */
// 对于自定义类型,判断内容是否一致,需要实现Equatable接口
class BookItem
let bookId: String
let title: String
init (bookId: String, title: String)
self.bookId = bookId
self.title = title
extension BookItem: Equatable
static func ==(lhs: BookItem, rhs: BookItem) -> Bool
// 具体判断规则根据实际需要进行
return lhs.bookId == rhs.bookId
3.9.2 使用===
和!==
判断class
类型对象是否同一个引用,而不是用==
和!=
推荐
if tenEighty === alsoTenEighty
/* ... */
if tenEighty !== notTenEighty
/* ... */
3.10 协议
3.10.1 当实现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.12 当方法最后一个参数是Closure类型,调用时建议使用尾随闭包语法, 但只在只存在一个闭包参数时才使用尾闭包。
推荐
UIView.animateWithDuration(1.0)
self.myView.alpha = 0
UIView.animateWithDuration(1.0,
animations:
self.myView.alpha = 0
,
completion: finished in
self.myView.removeFromSuperview()
)
不推荐
UIView.animateWithDuration(1.0, animations:
self.myView.alpha = 0
)
UIView.animateWithDuration(1.0,
animations:
self.myView.alpha = 0
) finished in
self.myView.removeFromSuperview()
3.13 高阶函数推荐最简化语法
推荐
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.14 访问控制 (优先考虑最低级)
-
private
-
fileprivate
-
internal
(默认忽略不写) -
public
-
open
访问控制权限关键字应该写在最前面,除了@IBOutlet
、@IBAction
、@discardableResult
、@objc
等关键字.
3.15 如调用者可以不使用方法的返回值,则需要使用@discardableResult
标明
推荐
@discardableResult
func print(message: String) -> String
let output = "Output : \\(message)"
print(output)
return output
3.16 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.17 循环引用
3.17.1 使用委托和协议时,避免循环引用,定义属性的时候使用weak修饰
推荐
public weak var dataSource: UITableViewDataSource?
public weak var delegate: UITableViewDelegate?
3.17.2 在逃逸Closures中使用self时避免循环引用
推荐
request(.list) [weak self] (result: Result<[Model]>) in
guard let self = self else return
self.items = self.result.value
self.tableView.reloadData()
不推荐
request(.list) [unowned self] (result: Result<[Model]>) in
self.items = self.result.value
self.tableView.reloadData()
不推荐
request(.list) [weak self] (result: Result<[Model]>) in
self?.items = self?.result.value
self?.tableView.reloadData()
3.18 空判断
推荐
if array.isEmpty
/* ... */
if string.isEmpty
/* ... */
不推荐
if array.count == 0
/* ... */
if string.count == 0
/* ... */
3.19 单例
推荐
class TestManager
static let shared = TestManager()
/* ... */
四. 项目规范
核心思想
简化一切繁琐代码, 复杂逻辑多方法分类拆分, 风格保持简洁优雅, 严谨易读 杜绝一切不安全情况.
复用封装视情况而定, 可以独立拆分的全部分离, 维护成本最小化, 保持整体工程高内聚低耦合, 业务尽可能模块化管理.
标准StoryBoard构建的ViewController结构示例
import UIKit
class SettingViewController: UIViewController
// 各种常量变量声明区域
// 顺序通常为 public -> private -> lazy -> IB -> Other
// 初始化优先使用Then
override func viewDidLoad()
super.viewDidLoad()
setup()
setupLayout()
setupNotification()
loadData()
// 其他IBAction
// 其他重写属性或方法
override var preferredStatusBarStyle: UIStatusBarStyle
return .default
static func instance() -> Self
return StoryBoard.setting.instance()
deinit
// 释放处理
extension SettingViewController
// public方法
extension SettingViewController
private func setup()
// 设置 添加子视图等
private func setupLayout()
// 设置布局
private func setupNotification()
// 设置通知监听
extension SettingViewController
// 事件方法
extension SettingViewController
// 数据请求方法
private func loadData()
/* ... */
extension SettingViewController
// 其他逻辑方法
extension SettingViewController
// 其他代理方法
图片等资源存储
优先使用Assets.xcassets
颜色 图片使用
推荐
// Color Literal
#colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
// Image Literal
#imageLiteral(resourceName: <#T##String#>)
公共组件设计准则
- 良好的可扩展性
- 严谨的逻辑思维
- 严格的访问权限
- 优雅的语法特性
- 合理的接口设计
- 通用的业务兼容
以上是关于Swift使用规范的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Swift 3.1 中的 API 创建解析数据,API 以括号开头和结尾
《从零开始学Swift》学习笔记(Day 57)——Swift编码规范之注释规范: