版本记录
版本号 | 时间 |
---|---|
V1.0 | 2018.12.4 |
前言
Swift是编写软件的绝佳方式,无论是用于手机,台式机,服务器还是其他任何运行代码的软件。它是一种安全,快速,交互式的编程语言,它将现代语言思维的最佳结合与来自更广泛的Apple工程文化的智慧和来自开源社区的各种贡献相结合。编译器针对性能进行了优化,语言针对开发进行了优化,而不会对其进行任何影响。
Swift对新程序员很友好。它是一种工业级编程语言,与脚本语言一样富有表现力和乐趣。在playground上编写Swift代码可以让您试验代码并立即查看结果,而无需构建和运行应用程序的开销。
正文
正确性
力争让代码没有编辑警告(warning
)。这个规则下衍生出了许多决定,如:使用#selector
方式,而不是直接使用字符串。
注意:由于iOS系统版本升级,同时App支持版本的问题,合理选择正确的未失效方法,可消除部分编译警告。
命名
描述性和一致性的命名会让代码更加的易读、易懂。命名请遵循一下规则:
- 追求调用方的清晰性
- 优先使用更清晰的命名,而不是更简洁的命名
- 使用驼峰样式
- 类型、协议名首字符大写,其他的都首字母小写
- 包含所有需要的单词,省略不必要的
- 使用基于角色的命名,而不是基于类型的
- 工厂方法使用make开头
- 对方法的命名
- 不要使用生僻的单词
- 通常不要用缩写
- 选用好的参数名来起到描述的作用
类前缀
Swift中的类型自动使⽤了其所在的模块作为命名空间,所以不必给类型加
前缀。如果来⾃不同模块的类型名字冲突,可以显示的使⽤模块名作为调⽤前缀来避免冲突。
建议
import SomeModule
import OtherModule
let someUsefulClass = SomeModule.UsefulClass()
let otherUsefulClass = OtherModule.UsefulClass()
代理
当定义一个代理⽅法时,第一个匿名参数应该是代理的源对象。( UIKit 中有许多这样的的例子)
建议
func numberOfSections(in tableView: UITableView) -> Int
使⽤可类型推导的上下⽂文
利用好编译器器的类型推断特性,来写出简短、清晰的代码。
建议
self.collectionView.backgroundColor = .white
泛型
泛型参数应当使⽤具有描述性的驼峰样式来命名。当泛型参数不具有
明确的关系或⻆⾊时,可使⽤⼀个⼤写的字母表示即可。如: T
, U
, V
使⽤的语⾔
应使⽤用美式英语的拼写⽅方式以匹配Apple的API,应尽量保持命名的可读性,不应该⽤多含义且有相反或者混淆意思的单词。
建议
let color = "white"
不建议
let colour = "white"
代码组织
尽可能的使⽤扩展(extensions
)来解耦你的代码,将代码划分到不同的扩展模块中,每个扩展尽量使用// MARK: -
开头,用以来更好的区分扩展。
协议的遵守
具体来讲,当让一个Model
遵守某个协议时,推荐添加一个独立的Model
扩展(extensions
)来遵守该协议。这样使得相关的协议⽅法能组织在一起。
对于 UIKit 的视图控制器(view controllers
),可以考虑将⽣生命周期(LifeCycle
)相关、⾃定义访问器( custom accessors )、 IBAction
独⽴不同的到类扩展中。
建议
// MARK: - UITableViewDelegate
extension XXViewController: UITableViewDataSource, UITableViewDelegate
⽆用的代码
⽆用的代码包括Xcode产⽣生的模板代码、占位的注释等、⽅法的默认实现仅仅是调用 super 等,这些都应当移除掉。
建议
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.dataList.count
}
不建议
// 该方法什么都没干,存在反而会增加小伙伴的阅读量
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
减小引入
保存最小的引入(imports
)。例如, 当只使用Foundation
时,不要引⼊入UIKit
。
空格
- 代码折行使用4个空格
- 方法的大括号和其他大括号(
if
/else
/switch
/while
),其左括号必须要和语句在同一个行,并且右括号要换行;
建议
if XXX == 1 {
// do something
} else {
// do something else
}
- 变量类型和冒号(
:
)之间保留一个空格;
建议
let cellHeight: CGFloat = 73.5
- 返回值标记(
->
)两侧各保留一个空格;
建议
func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect
- 各个方法之间必须有一个空格,这使得代码视觉上更清晰;
- 方法的实现中,应当适当的添加空行来划分功能。过多的空行意味着应该拆分这些功能到不同的方法中,通过这样来避免一个巨大的方法;
- 通常冒号(:)的左边应当没有空格,而在右边有一个空格。当然这个是有例外的,如:三目运算符、空字段、无参数方法等;
建议
var delegate: UICollectionViewDelegate?
注释
- 给方法或者属性添加注释,可以使用
option + command + /
来让Xcode自动生成,也可以使用MARK: -等;
option + command + /
效果如下
/// <#Description#>
///
/// - Parameters:
/// - pageNo: <#pageNo description#>
/// - lon: <#lon description#>
/// - lat: <#lat description#>
/// - state: <#state description#>
/// - responseComplete: <#responseComplete description#>
func requstNetData(_ pageNo: Int,
_ lon: Double,
_ lat: Double,
_ state: Int,
_ responseComplete: HttpComplete) {
}
- 给关键逻辑添加一些局部注释,单行注释请用
//
; - 注释要保持最新状态;
类与结构体
结构体(struct)是值类型,当事物不具有唯一性时,使用结构体。
类是引用类型,当事物具有唯一性或者有明确的生命周期时,使用类。
以下是一个类的定义
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))"
}
}
使用self
在Swift中,可以通过利用好编译器的类型推断特性省略self来访问一个独享的属性或者方法。但是为了消除使用的歧义,建议使用self来访问。
计算属性
为了简洁性,如果⼀个计算属性是只读(read-only
)的,那么应省略 get { ... }
语句。get { ... }
语句只在计算属性是读写( read-write )时,才要求使⽤。
建议
var area: Double {
return width * height
}
使用final标记
出于某些原因,你可能不希望一个类被继承,这时你可以将其标记为final
来表示它不不能被继承。
例如:一个单例,可能就不希望被继承。
函数声明
- 将简短的函数声明保留在一行中,包括左括号;
建议
func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes?
- 无返回值的函数可以省略(
-> Void
)返回值;
建议
func register(_ nib: UINib?, forCellWithReuseIdentifier identifier: String)
- 参数较多的函数可以像
Objective-C
中一样进行折行处理;
建议
func foo(arg1: Int,
arg2: Double,
arg3: String,
arg4: [Bool],
arg5: () -> Void) {
/* code goes here */
}
闭包表达式
当参数列表末尾只有一个闭包参数时,才应该使用尾随闭包语法。
对于使⽤闭包的链式调⽤,应当让代码更清晰、更易读。可以借助空格(spacing
)、换⾏(line breaks
)和匿名参数(anonymous arguments
)等⽅法来让代码更清晰、更易读,但这都依赖于你的选择。
类型
应尽量使用Swift
的原生类型,当然Swift
提供了对Objective-C
类型的桥接方法,你可以使用Objective-C
的所有方法。
建议
let width = 120.0 // Double
let widthString = (width as NSNumber).stringValue
常量
常量使用关键字let
定义,变量使用关键字var
定义。除非值可变,否则都应该用关键字let
定义。
在一个类型的内容,通过关键字static let
来定义静态常量,这样可以更好的组织这些静态变量。
建议
enum Math {
static let e = 2.718281828459045235360287
static let pi = 3.14159265358979323846264
}
类内部的静态方法和属性,有点类似于全局方法和属性。但应尽量避免使用全局方法和属性。有一些例外情况,比如当使用runtime
的objc_getAssociatedObjec()
函数时,需要定义一个全局的key来作为参数。
可选类型
当使用?
来定义可选类型时,表明它可以接受为nil
的值;
当使用!
来定义可选类型时,表明它可以接受为nil
的值,但必须保证在使用它时,值不为nil
;
使用可选绑定来一次性解包单个或多个可选类型值
类型推导
对于局部变量,尽量使用类型推导来让代码更紧凑。而对于成员变量来说,应尽量不要使用类型推导来让类的定义更清晰。
语法糖
利用语法糖,使用更简短的声明方式
内存管理
可以通过使用weak
和unowned
来避免循环引用,但也可以直接使用值类型(struct
,enum
)来避免循环引用。
可以通过guard let
的形式来产生strongSelf
建议
guard let sSelf = self else { return }
访问控制
一般来说,被标记为private
、fileprivate
的属性或方法都应以下划线(_
)开头。例外情况是,当标记被修饰为private(set)
、fileprivate(set)
时,不需要下划线(_
)开头,因为他们都是可访问的属性,只是他们都是只读属性而已。
建议
private var _isEnabled: Bool
fileprivate var _isClosed: Bool
private func _foo() {
// code goes here
}
fileprivate func _bar() {
// code goes here
}
private(set) var isEnabled: Bool
fileprivate(set) var isClosed: Bool
一般将访问控制标记放在声明的最前面,但例外情况中,当有属性标记@IBAction
、@IBOutlet
、@discardableResult
、@objc
时,需要将属性标记放在最前面。
建议
@IBOutlet private var _titleLab: UILabel!
控制流
优先使用for-in
的方式而不是while
建议
for (index, person) in attendeeList.enumerated() {
print("\(person) is at position #\(index)")
}
使用Guard语句
通过使用guard
来避免使用if
时代码块的深度嵌套问题
建议
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中不要求必须加分号,一般情况下你不需要使用分号。只有当你希望将多行代码写在一行时,才需要加分号来断句。
圆括号
一般情况下,在类型if
条件、for
循环等控制语句中不需要加圆空号。只有当你在进行数学运算时,希望代码可读性更高时才需要适当的添加圆括号。
建议
let result = ((x * y) + 2) / h