本文始发于我的博文团队Swift编码规范分享,现转发至此。
目录
- 命名
- 格式
- 准则
- 文件
- 场景
- 参考
命名
【强制】命名清晰,保持一致性
反例:displayName(返回name还是展示name)
【强制】代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式
说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使纯拼音命名方式也要避免采用。
正例:alibaba / taobao / youku / hangzhou 等国际通用的名称,可视同英文
反例:DaZhePromotion [打折]、getPingfenByName() [评分] / int 某变量 = 3
【强制】类、结构体、枚举、协议名使用大驼峰风格,常用缩写除外
正例:UserManager、UMSocialAdapter、TCPManager
【强制】函数、方法、变量、常量、参数使用小驼峰命名
【强制】协议名统一规范
作用为delegate,结尾添加Delegate;描述协议做的事,用名词描述;描述行为,用形容词,例如"able"或者"ing"等;如果两者不能满足,结尾添加Protocol。
正例:ScrollToTopable、UIDataSourceTranslating
【强制】缩略词使用完整大写,如果作为命名的开始部分,且首字母需要小写,则缩略词全小写
正例:
let userID = "123456"
let imageURL = "http://xxxxx"
class URLHandler {
func urlConvert(urlString: String) {}
}
【强制】枚举项小写
正例:
enum CompassPoint {
case north
case south
case east
case west
}
【强制】命名先保证表达的意思准确,再考虑简短,不为了缩短书写而缩短书写
说明:比如有些属性适合定义成类属性;有些准确的需要定义成实例属性。
正例:UIDevice.current.isIphoneX
反例:UIDevice.isIphoneX
【强制】常量、变量命名若不能明显表明类型,则属性命名内要包括类型信息
正例:
// 变量名中可以表明类型,则命名中不需要包括类型信息
let animationDuration: NSTimeInterval
let userName: String
// Controller命名
// UIViewController、UITableViewController等简写成Controller
let popupController: UIViewController
// UITabBarController和UINavigationController保留结构缩写
let flashSaleTabBarController: UITabBarController
// 命名中需要明确类型信息
let userImage: UIImage
let userImageURL: NSURL
let userImageURLString: String
// 当使用outlets时, 确保命名中标注类型
@IBOutlet weak var submitButton: UIButton!
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var nameLabel: UILabel!
【推荐】如果使用到了设计模式,建议在类名中体现出具体模式
说明:将设计模式体现在名字中,有利于阅读者快速理解架构设计思想。
正例:class CommunityFollowTopicCellFactory、class TopicListCellBaseFactory
【强制】如果枚举类型的属性,其命名不能表明是枚举类型的,带上Enum后缀
正例:UserIdentityEnum、sectionType、playStatus、selectionStyle
【强制】声明属性时言简意赅,不带上类名
正例:
// 系统 UIDevice.current
// 而不是UIDevice.currentDevice
UserDefaults.standard // 而不是UserDefaults.standardDefaults
class RouteManager {
static let shared = RouteManager() // 用shared,不用sharedManager
}
【强制】区分使用default或shared
说明:default一般用于提供使用默认的参数配置的实例;shared一般用于单例。
【强制】如果省略外部参数名后会导致调用处含义模糊,则禁止省略
反例:
// 方法声明
class func action(_ pageName: String?, pageParam: String?, action: String, actionParam: [String: Any]?, isOutPoint: Bool = false) {}
// 调用处 UserTracker.action("搜索", pageParam: searchType.rawValue, action: "语音输入", actionParam: ["keywords": result], isOutPoint: true)
【强制】函数命名中尽量不添加介词,如of、in、on、with等
正例:
// 原声明:UIFont.systemFontOfSize
open class func systemFont(ofSize fontSize: CGFloat) -> UIFont // 原声明:UIView.animateWithDuration
open class func animate(withDuration duration: TimeInterval, animations: @escaping () -> Swift.Void)
格式
【强制】如果语句的逻辑或长度较复杂,则使用变量保存再引用
反例:
AnyDataSourceService(dataSource: GoodsCommentResultDataSource(id: goodsId, offset: offset, imageOnly: imageOnly)).run(success: {
[weak self] (data: GoodsCommentResult) in
})
正例:
let dataSource = GoodsCommentResultDataSource(id: goodsId, offset: offset, imageOnly: imageOnly)
let service = AnyDataSourceService(dataSource: dataSource)
service.run(success: { [weak self] (data: GoodsCommentResult) in
})
【强制】如果大括号内为空,则简洁地写成{}即可,不需要换行
【强制】枚举每一个case操作都换行,不跟在“:”后面
switch enum {
case a:
methodA()
case b:
methodB()
case c:
methodC()
}
【推荐】如果switch内每一个case的操作大于5行,则封装成一个方法调用
【强制】变量类型,函数参数,遵循协议或继承父类,分号前不留空格
正例:
let str: String = "Test"
someFunction(someArgument: "Argument")
class ViewController: UIViewController {}
extension ViewController: UITableViewDelegate {}
【强制】逗号后面、运算符前后加空格
正例:
let array = [1, 2, 3, 4, 5]
let sum = 1 + 2
let isSuccess = sum == 3
【强制】左大括号不换行,左边保留空格
【强制】流程控制不使用小括号
正例:if x == y { }
【强制】使用枚举时用简写
正例:imageView.setImageWithURL(url, type: .person)
【强制】使用一些语句如 else,catch等紧随代码块的关键词的时候,确保代码块和关键词在同一行
正例:
do {
try canThrowAnError() // no error was thrown
} catch {
// an error was thrown
}
if name == "world" {
print("hello, world")
} else {
print("I'm sorry \(name), but I don't recognize you")
}
【强制】switch与case对齐
正例:
switch some value to consider {
case value 1:
respond to value 1
case value 2, value 3:
respond to value 2 or 3
default:
otherwise, do something else
}
【强制】不注释无用代码,直接删掉。若想保留代码以防以后用到,请使用git
【强制】文件末尾必须留且只留一行空白行
【强制】“//”注释符号后面要保留空格
【强制】求高度/字符串等较复杂时需按一下格式定义,清晰指明含义,方便他人维护
let factor1Top = 20
var factor1Height = 40
var factor2Height = 40
let bottomPadding = 30
if lineCount > 0 {
let lineHeight = lineCount * 10
factor1Height += lineHeight
}
if lineCount > 2 {
let lineHeight = lineCount * 20
factor2Height += lineHeight
}
let height = factor1Top + factor1Height + factor2Height + bottomPadding
return CGSize(width: width, height: height)
准则
【强制】若变量类型可以依靠推断得出,则声明时不要指明类型
正例:
let π = 3.14159
【强制】模型中需要指明数据类型
正例:
struct DiamondPackage {
var id: Int = 0
var count: Int = 0
var price: Double = 0.0
var desc: String?
var descIconURL: NSURL?
var iapProductId: String?
}
【强制】使用隐式拆包可选类型的场景只能是@IBOutlets和网络层Service(保证使用之前肯定有值非空时),其余情况禁止使用“!”隐式拆包
【强制】若需要判断当前值是否为nil,直接和nil比较
正例:if someOptional != nil {}
反例:if let _ = someOptional {}
【强制】使用属性时不用self.修饰
【强制】使用guard代替if提前返回
【强制】使用guard拆包多个可选值
正例:
guard let thingOne = thingOne, let thingTwo = thingTwo, let thingThree = thingThree else {
return
}
【强制】严格设置访问权限open/public/internal/fileprivate/private
【强制】不使用的库不import进文件
说明:一般新建文件之后都会有默认代码:import Foundation,不需要则删除
文件
【强制】Controller文件结构
说明:Controller包含较多代码,需要适量划分,使得代码查找更方便
一般包含以下内容:
import
@IBOutlet
@IBAction
override
配置数据源(configSection和enum Row)
私有属性 开放属性 私有函数 开放函数
delegate/protocol
正例:
// import放最前面,先import系统库
import UIKit
import Alamofire
protocol ViewControllerDelegate: class {}
class ViewController: UIViewController {
// 仅包含@IBOutlet、@IBAction、私有属性、公有属性、override方法
// 顺序依次如下
// IBOutlet
@IBOutlet var imageView: UIImageView!
// 公有属性
var showBottom: Bool = false
// 私有属性
private weak var delegate: ViewControllerDelegate?
private var rows: [Row] = []
override func viewDidLoad() {
super.viewDidLoad()
configVM()
doSomething()
// Do any additional setup after loading the view, typically from a nib.
}
// override按生命周期顺序
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
}
// 每个extension内第一行空行
// @IBAction
extension ViewController {
@IBAction func clickButton() {}
}
// 类方法、开放的方法
extension ViewController {
class func classMethod() {}
func openMethod() {}
}
// 私有的方法
private extension ViewController {
func doSomething() {}
}
// 协议,每个协议分开写
extension ViewController: UITableViewDelegate {}
extension ViewController: ScrollToTop {}
// 数据源配置相关放最后的extension
private extension ViewController {
enum Row {
case row1
case row2
case row3
}
func configVM() {
rows = []
rows.append(.row1)
}
}
场景
- 定义模型
【强制】唯一标识统一用id,不使用类似jobId写法
【强制】不参与运算的String不需要初始化,如name,desc等仅用于显示的字段
【强制】数组必须初始化,不使用optional写法
- 使用CocoaPods
【强制】导入库需要指定某一个确定的版本号,禁止使用大于等于之类的指定
【强制】修改第三方库(禁止修改,除非特殊情况)需要新建一个Pod,并且在提交podfile修改的commit中注释原因
【强制】不轻易引入第三方库,除了网络库、JSON转模型库、路由库等
【强制】保持相同作用的库仅有一个
【推荐】团队开发的库尽量引入framework,不引入源码
参考
swift-style-guide
最详尽的 Swift 代码规范指南
17条 Swift开发规范 最佳实践
The Swift Programming Language (Swift 4)
-END-
欢迎到我的博客交流:https://zackzheng.info