转载

Swift-Code-Style

Swift-Code-Style

投稿文章,作者:南栀倾寒(博客

最近工作也比较稳定了,公司在做代码规范和组件化的跳转。 鉴于使用Objective-C的开发成员比较多, 我们架构师就整理了Objective-C的代码规范。不过作为Swift开发的老司机,也整理了一套适用与Swift的代码规范。 以后可以直接拿来用了。

注释

 // 单行注释  /*  多行注释  */  /// 标记注释1  /** 标记注释2 */

建议使用VVDocument-Xode插件

文档注释

以/* ..../ 标记, 不用再没一行开头都加*号,支持markdown书写,例如:

/**  ## Feature Support  This class does some awesome things. It supports:  - Feature 1  - Feature 2  - Feature 3  ## Examples  Here is an example use case indented by four spaces because that indicates a  code block:      let myAwesomeThing = MyAwesomeClass()      myAwesomeThing.makeMoney()  ## Warnings  There are some things you should be careful of:  1. Thing one  2. Thing two  3. Thing three  */ class MyAwesomeClass {     /* ... */ }

方法注释

用 - parameter注释来标记参数等

/**  This does something with a `UIViewController`, perchance.  - warning: Make sure that `someValue` is `true` before running this function.  */ func myFunction() {     /* ... */ }

命名

使用可读的驼峰命名法去给类 方法 变量 命名。 class struct protocol enum 应使用大写,变量名使用小写

private let maximumWidgetCount = 100 class WidgetContainer {   var widgetButton: UIButton   let widgetHeightPercentage = 0.85 }

对于全局函数,init方法 ,建议每个参数都使用外部变量,来保证可读性

func dateFromString(dateString: String) -> NSDate func convertPointAt(column column: Int, row: Int) -> CGPoint func timedAction(afterDelay delay: NSTimeInterval, perform action: SKAction) -> SKAction! // would be called like this: dateFromString("2014-03-14") convertPointAt(column: 42, row: 13) timedAction(afterDelay: 1.0, perform: someOtherAction)

Protocols 协议命名

建议遵守Apple's API DesignGuidelines使用名词来描述,如 ing able ible,例如

Collection WidgerFactory Equtable Resizing

Emumerations 枚举命名规范

使用首字母小写的驼峰命名法给每个case命名

enum Shape {   case rectangle   case square   case rightTriangle   case equilateralTriangle }

Class Prefixes类型前缀

官方建议不使用前缀,因为swift有命名空间的概念

但是由于在项目开发中不可避免使用开源库,大部分使用pods管理,但是有时候需要针对需要定制功能,直接修改源码,这时候是直接将源码放在工程中,而且大部分的项目都是混编项目。可能导致命名冲突,此处还建议用LJ(Lianjia)当作命名前缀

class LJHomeViewController: UIViewController {}

Selector选择器

建议使用可推测的上下文环境,来创建选择器,而不是点击Xcode的Fix it ,这样会产生一个全名称 选择器

let sel = #selector(viewDidLoad)

不推荐

let sel = #selector(ViewController.viewDidLoad)

Generics泛型

泛型命名应该使用大写的驼峰命名法,,如果给一个泛型起名字其实没意义,可以使用常见的T,U,V来命名

推荐

struct Stack{ ... } func writeTo(inout target: Target) func max(x: T, _ y: T) -> T

不推荐

struct Stack{ ... }//命名无意义 func writeTo(inout t: target)// 首字母未大写 func max(x: Thing, _ y: Thing) -> Thing//简称即可

Code Formatting 代码格式

留空白

  • 建议使用tabs 而不是使用空格

  • 文件结束时留一行空白

  • 用足够的空行把代码分割为合理的逻辑块,而不是非常紧凑

  • 不要在一行代码结尾处留空格

  • 更不要在空行(/n)中使用缩进(/t)

声明类型时,将冒号与标识符连在一起

当声明一个变量时冒号紧跟变量,空一格再写类型

class SmallBatchSustainableFairtrade: Coffee { ... } let timeToCoffee: NSTimeInterval = 2 func makeCoffee(type: CoffeeType) -> Coffee { ... }

Control Flow 控制流

建议使用Swift范的for in 循环而不是 while or c 式for循环

for _ in 0..<3 {   print("Hello three times") } for (index, person) in attendeeList.enumerate() {   print("/(person) is at position #/(index)") } for index in 0.stride(to: items.count, by: 2) {   print(index) } for index in (0...3).reverse() {   //3,2,1,0   print(index) }

代码块缩进

(if/else/switch/while etc.)或者method function 的大括号留在当前行,并前保留一个空格 ,能省略的不要添加

if user.isHappy {   // Do something } else {   // Do something else }

不推荐

if (user.isHappy ) 多余空格 {                  换行位置不对   // Do something } else {   // Do something else }

Early Return

当你遇到某些操作需要条件判断去执行,应该使用防御式编程 尽早返回

guard n.isNumber else {     return } guard let number1 = number1, number2 = number2, number3 = number3 else { fatalError("impossible") } // do something with numbers // Use n here //guard 理解为确保的意思,  如 确保n是一个数字 不推荐使用if判断 if n.isNumber {     // Use n here } else {     return } if let number1 = number1 {   if let number2 = number2 {     if let number3 = number3 {       // do something with numbers     }     else {       fatalError("impossible")     }   }   else {     fatalError("impossible")   } } else {   fatalError("impossible") }

Semicolons 分号

不要写分号,不要写分号,不要写分号 Swift不同于JavaScript ,详情参看:

generally considered unsafe---Do you recommend using semicolons after every statement in JavaScript?

更不建议把多句代码块放在一行中

自定义运算符的时候左右尽量各保留一个空格

func <|(lhs: rhs:="" -=""> Int func <|<(lhs: A, rhs: A) -> A // 重构后 func <| lhs:="" rhs:="" -=""> Int func <|< (lhs: A, rhs: A) -> A

代码分割

使用良好的代码分割让你的代码块更具有逻辑性

// MARK: -      类似@parma mark - // MARK:        类似@parma mark

ProtocolConformance 协议保持一致性

一个类型实现一个协议时建议单独声明一个扩展,保证逻辑性分离

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 }

无用的代码要删除

无用的代码和注释要删除 ,避免给阅读代码的人造成困惑和疑问

类型定义

尽可能的使用swift自带类型,在必须的时候才做桥接 ,String-> NSString , Set->NSSet

更多的使用let,而不是var

尽量let foo = something 而非 var  for = somthing

let-有保障 并且它的值的永远不会改变,对同事也是个 清晰的标记,对于它的用法,之后的代码可以做个强而有力的推断。更容易明白代码的含义。否则的话一旦你用了 var,还要去考虑值会不会改变,这时候你就不得不人肉去检查。

这样,无论何时你看到 var,就假设它会变,并找到原因。

常量

不建议直接命名顶级变量,建议定义在结构体或者枚举内部,用static let 声明。 可以给这些变量一个合适的命名空间

enum Math {   static let e  = 2.718281828459045235360287   static let pi = 3.141592653589793238462643 } radius * Math.pi * 2 // circumference

Optional可选类型

尽量不要使用强制解包

对于一个可选类型var foo = Type? 不要使用强制解包

foo!.doSomethind()

使用可选绑定,或者  可选链操作

if let foo = foo {     // Use unwrapped `foo` value in here } else {     // If appropriate, handle the case where the optional is nil } //或者 // Call the function if `foo` is not nil. If `foo` is nil, ignore we ever tried to make the call foo?.callSomethingIfFooIsNotNil()

避免使用隐式可选类型

如果 foo 可能为 nil ,尽可能的用 let foo: FooType? 代替 let foo: FooType!(注意:一般情况下,?可以代替!)

Struct Initializers 结构体初始化

使用结构体初始化而不是CGGet。。。之类的创建方法

let bounds = CGRect(x: 40, y: 20, width: 120, height: 80) let centerPoint = CGPoint(x: 96, y: 42)

Lazy Initialization

对于较大开销的初始化或者配置较多的初始化建议放在加载属性里

lazy var locationManager: CLLocationManager = self.makeLocationManager() private func makeLocationManager() -> CLLocationManager {   let manager = CLLocationManager()   manager.desiredAccuracy = kCLLocationAccuracyBest   manager.delegate = self   manager.requestAlwaysAuthorization()   return manager }

Classes and Structures 结构体和类

首选struct而非class

在非必需(比如没有生命周期)的时候使用struct,因为多态可以使用protocl实现 继承可以使用组合实现

值类型容易辨别,更可以用let去推测不可变的行为

只有在必须时才使用self

忘掉Objective-C到底时使用self.pro 还是_ivar的访问方式,对于swift内部调用properties或者method省略掉self

private class History {     var events: [Event]     func rewrite() {         events = []     } }

只有在使用闭包或者命名冲突时再加上self

extension History {     init(events: [Event]) {         self.events = events     }     var whenVictorious: () -> () {         return {             self.rewrite()         }     } }

只有在使用闭包时self 增强了被捕获的语义,其它时候是冗余的

对于只读的属性或者下标语法,使用隐式的getter方法

建议

var myGreatProperty: Int {     return 4 } subscript(index: Int) -> T {     return objects[index] }

不建议完整的写法,比较繁琐

var myGreatProperty: Int {     get {         return 4     } } subscript(index: Int) -> T {     get {         return objects[index]     } }

请把class默认标记为final

组合通常比继承更合适,而且不用 继承意味着考虑的更加健壮

// Turn any generic type into a reference type using this Box class. final class Box{   let value: T   init(_ value: T) {     self.value = value   } }

类型推断

能让系统推断的类型不要显示指明

struct Composite{     func compose(other: Composite) -> Composite{         return Composite(self, other)     } } let num:Int = 4

重构为

struct Composite{     func compose(other: Composite) -> Composite {         return Composite(self, other)     } } let num = 4

空的字典和空数组的类型 使用类型标记 加强语义

var names: [String] = [] var lookup: [String: Int] = [:]

函数声明

函数名要简短清晰,如果能保持在一行内,大括号也要保持在一行,如果不能换行并用Tab/b缩进

func reticulateSplines(spline: [Double]) -> Bool {   // reticulate code goes here } func reticulateSplines(spline: [Double], adjustmentFactor: Double,     translateConstant: Int, comment: String) -> Bool {   // reticulate code goes here }

闭包表达式

使用尾随闭包提高可读性,

UIView.animateWithDuration(1.0) {   self.myView.alpha = 0 } UIView.animateWithDuration(1.0,   animations: {     self.myView.alpha = 0   },   completion: { finished in     self.myView.removeFromSuperview()   } )

常见的闭包语义可以使用其缩略形式

let value = numbers.map { $0 * 2 }.filter { $0 % 3 == 0 }.indexOf(90) let value = numbers    .map {$0 * 2}    .filter {$0 > 50}    .map {$0 + 10}

Syntactic Sugar语法糖

对于有语法糖的建议使用,提升可读性

var deviceModels: [String] var employees: [Int: String] var faxNumber: Int?

而不是

var deviceModels: Array var employees: Dictionary var faxNumber: Optional

内存管理

对于class类型需要注意内存管理

普通的闭包建议使用[weak self] 或者[unowned self] 对于异步的闭包建议使用 [weak self] and  guard let strongSelf = self else { return }搭配使用

weak 避免出现循环引用, strongself 避免在异步回调中 捕获列表中捕获的变量被析构

resource.request().onComplete { [weak self] response in   guard let strongSelf = self else { return }   let model = strongSelf.updateModel(response)   strongSelf.updateUI(model) }

对于顶级类型,函数,变量定义,明确的列出权限控制

对于全局变量 顶级函数,类型,永远应该有着详尽的权限控制说明符

public var whoopsGlobalState: Int internal struct TheFez {} private func doTheThings(things: [Thing]) {}

参考自

Github

LinkedIn

Prolificinterative

Raywenderlich

正文到此结束
Loading...