最详尽的 Swift 代码规范指南

取证知识点1.0 取证1.0 阅读详情

img (80).jpg

1. 代码格式

1.1 使用四个空格进行缩进。

1.2 每行最多160个字符,这样可以避免一行过长。 (Xcode->Preferences->Text Editing->Page guide at column: 设置成160即可)

1.3 确保每个文件结尾都有空白行。

1.4 确保每行都不以空白字符作为结尾 (Xcode->Preferences->Text Editing->Automatically trim trailing whitespace + Including whitespace-only lines).

1.5 左大括号不用另起一行。

1
2
3
4
5
6
7
8
9
10
11
12
class SomeClass {
     func someMethod() {
         if  x == y {
             /* ... */
         }  else  if  x == z {
             /* ... */
         }  else  {
             /* ... */
         }
     }
     /* ... */
}

1.6 当在写一个变量类型,一个字典里的主键,一个函数的参数,遵从一个协议,或一个父类,不用在分号前添加空格。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 指定类型
let pirateViewController: PirateViewController
// 字典语法(注意这里是向左对齐而不是分号对齐)
let ninjaDictionary: [String: AnyObject] = [
     "fightLikeDairyFarmer" :  false ,
     "disgusting" :  true
]
// 声明函数
func myFunction<t, u: someprotocol where t.relatedtype == u>(firstArgument: U, secondArgument: T) {
     /* ... */
}
// 调用函数
someFunction(someArgument:  "Kitten" )
// 父类
class PirateViewController: UIViewController {
     /* ... */
}
// 协议
extension PirateViewController: UITableViewDataSource {
     /* ... */
}</t, u: someprotocol where t.relatedtype == u>

1.7 基本来说,要在逗号后面加空格。

1
let myArray = [1, 2, 3, 4, 5]

1.8 二元运算符(+, ==, 或->)的前后都需要添加空格,左小括号后面和右小括号前面不需要空格。

1
2
3
4
5
6
7
let myValue = 20 + (30 / 2) * 3
if  1 + 1 == 3 {
     fatalError( "The universe is broken." )
}
func pancake() -> Pancake {
     /* ... */
}

1.9  遵守Xcode内置的缩进格式( 如果已经遵守,按下CTRL-i 组合键文件格式没有变化)。当声明的一个函数需要跨多行时,推荐使用Xcode默认的格式,目前Xcode 版本是 7.3。

1
2
3
4
5
6
7
8
9
10
11
12
13
// Xcode针对跨多行函数声明缩进
func myFunctionWithManyParameters(parameterOne: String,
                                   parameterTwo: String,
                                   parameterThree: String) {
     // Xcode会自动缩进
     print( "\(parameterOne) \(parameterTwo) \(parameterThree)" )
}
// Xcode针对多行 if 语句的缩进
if  myFirstVariable > (mySecondVariable + myThirdVariable)
     && myFourthVariable == .SomeEnumValue {
     // Xcode会自动缩进
     print( "Hello, World!" )
}

1.10 当调用的函数有多个参数时,每一个参数另起一行,并比函数名多一个缩进。

1
2
3
4
someFunctionWithManyArguments(
     firstArgument:  "Hello, I am a string" ,
     secondArgument: resultFromSomeFunction()
     thirdArgument: someOtherLocalVariable)

1.11 当遇到需要处理的数组或字典内容较多需要多行显示时,需把 [ 和 ] 类似于方法体里的括号, 方法体里的闭包也要做类似处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
someFunctionWithABunchOfArguments(
     someStringArgument:  "hello I am a string" ,
     someArrayArgument: [
         "dadada daaaa daaaa dadada daaaa daaaa dadada daaaa daaaa" ,
         "string one is crazy - what is it thinking?"
     ],
     someDictionaryArgument: [
         "dictionary key 1" :  "some value 1, but also some more text here" ,
         "dictionary key 2" :  "some value 2"
     ],
     someClosure: { parameter1  in
         print(parameter1)
     })

1.12 应尽量避免出现多行断言,可使用本地变量或其他策略。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 推荐
let firstCondition = x == firstReallyReallyLongPredicateFunction()
let secondCondition = y == secondReallyReallyLongPredicateFunction()
let thirdCondition = z == thirdReallyReallyLongPredicateFunction()
if  firstCondition && secondCondition && thirdCondition {
     // 你要干什么
}
// 不推荐
if  x == firstReallyReallyLongPredicateFunction()
     && y == secondReallyReallyLongPredicateFunction()
     && z == thirdReallyReallyLongPredicateFunction() {
     // 你要干什么
}

2. 命名

2.1 在Swift中不用如Objective-C式 一样添加前缀 (如使用 GuybrushThreepwoode 而不是 LIGuybrushThreepwood)。

2.2 使用帕斯卡拼写法(又名大骆驼拼写法,首字母大写)为类型命名 (如 struct, enum, class, typedef, associatedtype 等)。

2.3 使用小骆驼拼写法 (首字母小写) 为函数,方法,变量,常量,参数等命名。

2.4 首字母缩略词在命名中一般来说都是全部大写,例外的情形是如果首字母缩略词是一个命名的开始部分,而这个命名需要小写字母作为开头,这种情形下首字母缩略词全部小写。

1
2
3
4
5
6
7
8
// "HTML" 是变量名的开头, 需要全部小写 "html"
let htmlBodyContent: String =  "<p>Hello, World!</p>"
// 推荐使用 ID 而不是 Id
let profileID: Int = 1
// 推荐使用 URLFinder 而不是 UrlFinder
class URLFinder {
     /* ... */
}

2.5 使用前缀 k + 大骆驼命名法 为所有非单例的静态常量命名。

1
2
3
4
5
6
7
8
9
class MyClassName {
     // 基元常量使用 k 作为前缀
     static let kSomeConstantHeight: CGFloat = 80.0
     // 非基元常量也是用 k 作为前缀
     static let kDeleteButtonColor = UIColor.redColor()
     // 对于单例不要使用k作为前缀
     static let sharedInstance = MyClassName()
     /* ... */
}

2.6 对于泛型和关联类型,可以使用单个大写字母,也可是遵从大骆驼命名方式并能描述泛型的单词。如果这个单词和要实现的协议或继承的父类有冲突,可以为相关类型或泛型名字添加 Type 作为后缀。

1
2
3
4
5
6
7
8
class SomeClass<t> {  /* ... */  }
class SomeClass<model> {  /* ... */  }
protocol Modelable {
     associatedtype Model
}
protocol Sequence {
     associatedtype IteratorType: Iterator
}</model></t>

2.7 命名应该具有描述性 和 清晰的。

1
2
3
4
// 推荐
class RoundAnimatingButton: UIButton {  /* ... */  }
// 不推荐
class CustomButton: UIButton {  /* ... */  }

2.8 不要缩写,简写命名,或用单个字母命名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 推荐
class RoundAnimatingButton: UIButton {
     let animationDuration: NSTimeInterval
     func startAnimating() {
         let firstSubview = subviews.first
     }
}
// 不推荐
class RoundAnimating: UIButton {
     let aniDur: NSTimeInterval
     func srtAnmating() {
         let v = subviews.first
     }
}

2.9 如果原有命名不能明显表明类型,则属性命名内要包括类型信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 推荐
class ConnectionTableViewCell: UITableViewCell {
     let personImageView: UIImageView
     let animationDuration: NSTimeInterval
     // 作为属性名的firstName,很明显是字符串类型,所以不用在命名里不用包含String
     let firstName: String
     // 虽然不推荐, 这里用 Controller 代替 ViewController 也可以。
     let popupController: UIViewController
     let popupViewController: UIViewController
     // 如果需要使用UIViewController的子类,如TableViewController, CollectionViewController, SplitViewController, 等,需要在命名里标名类型。
     let popupTableViewController: UITableViewController
     // 当使用outlets时, 确保命名中标注类型。
     @IBOutlet weak  var  submitButton: UIButton!
     @IBOutlet weak  var  emailTextField: UITextField!
     @IBOutlet weak  var  nameLabel: UILabel!
}
// 不推荐
class ConnectionTableViewCell: UITableViewCell {
     // 这个不是 UIImage, 不应该以Image 为结尾命名。
     // 建议使用 personImageView
     let personImage: UIImageView
     // 这个不是String,应该命名为 textLabel
     let text: UILabel
     // animation 不能清晰表达出时间间隔
     // 建议使用 animationDuration 或 animationTimeInterval
     let animation: NSTimeInterval
     // transition 不能清晰表达出是String
     // 建议使用 transitionText 或 transitionString
     let transition: String
     // 这个是ViewController,不是View
     let popupView: UIViewController
     // 由于不建议使用缩写,这里建议使用 ViewController替换 VC
     let popupVC: UIViewController
     // 技术上讲这个变量是 UIViewController, 但应该表达出这个变量是TableViewController
     let popupViewController: UITableViewController
     // 为了保持一致性,建议把类型放到变量的结尾,而不是开始,如submitButton
     @IBOutlet weak  var  btnSubmit: UIButton!
     @IBOutlet weak  var  buttonSubmit: UIButton!
     // 在使用outlets 时,变量名内应包含类型名。
     // 这里建议使用 firstNameLabel
     @IBOutlet weak  var  firstName: UILabel!
}

2.10 当给函数参数命名时,要确保函数能理解每个参数的目的。

2.11 根据苹果接口设计指导文档, 如果协议描述的是协议做的事应该命名为名词(如Collection) ,如果描述的是行为,需添加后缀 able 或 ing (如Equatable 和 ProgressReporting)。 如果上述两者都不能满足需求,可以添加Protocol作为后缀,例子见下面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 这个协议描述的是协议能做的事,应该命名为名词。
protocol TableViewSectionProvider {
     func rowHeight(atRow row: Int) -> CGFloat
     var  numberOfRows: Int { get }
     /* ... */
}
// 这个协议表达的是行为, 以able最为后缀
protocol Loggable {
     func logCurrentState()
     /* ... */
}
// 因为已经定义类InputTextView,如果依然需要定义相关协议,可以添加Protocol作为后缀。
protocol InputTextViewProtocol {
     func sendTrackingEvent()
     func inputText() -> String
     /* ... */
}

3. 代码风格

3.1 综合

3.1.1 尽可能的多使用let,少使用var。

3.1.2 当需要遍历一个集合并变形成另一个集合时,推荐使用函数 map, filter 和 reduce。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 推荐
let stringOfInts = [1, 2, 3].flatMap { String($0) }
// ["1", "2", "3"]
// 不推荐
var  stringOfInts: [String] = []
for  integer  in  [1, 2, 3] {
     stringOfInts.append(String(integer))
}
// 推荐
let evenNumbers = [4, 8, 15, 16, 23, 42].filter { $0 % 2 == 0 }
// [4, 8, 16, 42]
// 不推荐
var  evenNumbers: [Int] = []
for  integer  in  [4, 8, 15, 16, 23, 42] {
     if  integer % 2 == 0 {
         evenNumbers(integer)
     }
}

3.1.3 如果变量类型可以依靠推断得出,不建议声明变量时指明类型。

3.1.4 如果一个函数有多个返回值,推荐使用 元组 而不是 inout 参数, 如果你见到一个元组多次,建议使用typealias ,而如果返回的元组有三个或多于三个以上的元素,建议使用结构体或类。

1
2
3
4
5
6
func pirateName() -> (firstName: String, lastName: String) {
     return  ( "Guybrush" ,  "Threepwood" )
}
let name = pirateName()
let firstName = name.firstName
let lastName = name.lastName

3.1.5 当使用委托和协议时,请注意避免出现循环引用,基本上是在定义属性的时候使用 weak 修饰。

3.1.6 在闭包里使用 self 的时候要注意出现循环引用,使用捕获列表可以避免这一点。

1
2
3
4
5
6
7
8
9
myFunctionWithClosure() { [weak self] (error) -> Void  in
     // 方案 1
     self?.doSomething()
     // 或方案 2
     guard let strongSelf = self  else  {
         return
     }
     strongSelf.doSomething()
}

3.1.7 Switch 模块中不用显式使用break。

3.1.8 断言流程控制的时候不要使用小括号。

1
2
3
4
5
6
7
8
// 推荐
if  x == y {
     /* ... */
}
// 不推荐
if  (x == y) {
     /* ... */
}

3.1.9 在写枚举类型的时候,尽量简写。

1
2
3
4
// 推荐
imageView.setImageWithURL(url, type: .person)
// 不推荐
imageView.setImageWithURL(url, type: AsyncImageView.Type.person)

3.1.10 在使用类方法的时候不用简写,因为类方法不如 枚举 类型一样,可以根据轻易地推导出上下文。

1
2
3
4
// 推荐
imageView.backgroundColor = UIColor.whiteColor()
// 不推荐
imageView.backgroundColor = .whiteColor()

3.1.11 不建议使用用self.修饰除非需要。

3.1.12 在新写一个方法的时候,需要衡量这个方法是否将来会被重写,如果不是,请用 final 关键词修饰,这样阻止方法被重写。一般来说,final 方法可以优化编译速度,在合适的时候可以大胆使用它。但需要注意的是,在一个公开发布的代码库中使用 final 和本地项目中使用 final 的影响差别很大的。

3.1.13 在使用一些语句如 else,catch等紧随代码块的关键词的时候,确保代码块和关键词在同一行。下面 if/else 和 do/catch 的例子.

1
2
3
4
5
6
7
8
9
10
if  someBoolean {
     // 你想要什么
}  else  {
     // 你不想做什么
}
do  {
     let fileContents =  try  readFile( "filename.txt" )
}  catch  {
     print(error)
}

3.2 访问控制修饰符

3.2.1 如果需要把访问修饰符放到第一个位置。

1
2
3
4
// 推荐
private static let kMyPrivateNumber: Int
// 不推荐
static private let kMyPrivateNumber: Int

3.2.2 访问修饰符不应单独另起一行,应和访问修饰符描述的对象保持在同一行。

1
2
3
4
5
6
7
8
9
// 推荐
public class Pirate {
     /* ... */
}
// 不推荐
public
class Pirate {
     /* ... */
}

3.2.3  默认的访问控制修饰符是 internal, 如果需要使用internal 可以省略不写。

3.2.4 当一个变量需要被单元测试 访问时,需要声明为 internal 类型来使用@testable import {ModuleName}。 如果一个变量实际上是private 类型,而因为单元测试需要被声明为 internal 类型,确定添加合适的注释文档来解释为什么这么做。这里添加注释推荐使用 - warning: 标记语法。

1
2
3
4
5
/**
  这个变量是private 名字
  - warning: 定义为 internal 而不是 private 为了 `@testable`.
  */
let pirateName =  "LeChuck"

3.3 自定义操作符

不推荐使用自定义操作符,如果需要创建函数来替代。

在重写操作符之前,请慎重考虑是否有充分的理由一定要在全局范围内创建新的操作符,而不是使用其他策略。

你可以重载现有的操作符来支持新的类型(特别是 ==),但是新定义的必须保留操作符的原来含义,比如 == 必须用来测试是否相等并返回布尔值。

3.4 Switch 语句 和 枚举

3.4.1 在使用 Switch 语句时,如果选项是有限集合时,不要使用default,相反地,把一些不用的选项放到底部,并用 break 关键词 阻止其执行。

3.4.2 因为Swift 中的 switch 选项默认是包含break的, 如果不需要不用使用 break 关键词。

3.4.3 case 语句 应和 switch 语句左对齐,并在 标准的 default 上面。

3.4.4 当定义的选项有关联值时,确保关联值有恰当的名称,而不只是类型。(如. 使用 case Hunger(hungerLevel: Int) 而不是 case Hunger(Int)).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum Problem {
     case  attitude
     case  hair
     case  hunger(hungerLevel: Int)
}
func handleProblem(problem: Problem) {
     switch  problem {
     case  .attitude:
         print( "At least I don't have a hair problem." )
     case  .hair:
         print( "Your barber didn't know when to stop." )
     case  .hunger(let hungerLevel):
         print( "The hunger level is \(hungerLevel)." )
     }
}

3.4.5 推荐尽可能使用fall through。

3.4.6 如果default 的选项不应该触发,可以抛出错误 或 断言类似的做法。

1
2
3
4
5
6
func handleDigit(digit: Int) throws {
     case  0, 1, 2, 3, 4, 5, 6, 7, 8, 9:
         print( "Yes, \(digit) is a digit!" )
     default :
         throw  Error(message:  "The given number was not a digit." )
}

3.5 可选类型

3.5.1 唯一使用隐式拆包可选型(implicitly unwrapped optionals)的场景是结合@IBOutlets,在其他场景使用 非可选类型 和 常规可选类型,即使有的场景你确定有的变量使用的时候永远不会为 nil, 但这样做可以保持一致性和程序更加健壮。

3.5.2 不要使用 as! 或 try!。

3.5.3 如果对于一个变量你不打算声明为可选类型,但当需要检查变量值是否为 nil,推荐用当前值和 nil 直接比较,而不推荐使用 if let 语法。

1
2
3
4
5
6
7
8
// 推荐
if  someOptional != nil {
     // 你要做什么
}
// 不推荐
if  let _ = someOptional {
     // 你要做什么
}

3.5.4 不要使用 unowned,unowned 和 weak 变量基本上等价,并且都是隐式拆包( unowned 在引用计数上有少许性能优化),由于不推荐使用隐式拆包,也不推荐使用unowned 变量。

1
2
3
4
5
6
7
8
9
// 推荐
weak  var  parentViewController: UIViewController?
// 不推荐
weak  var  parentViewController: UIViewController!
unowned  var  parentViewController: UIViewController
3.5.5 当拆包取值时,使用和被拆包取值变量相同的名称。
guard let myVariable = myVariable  else  {
     return
}

3.6 协议

在实现协议的时候,有两种方式来组织你的代码:

使用 // MARK: 注释来分割协议实现和其他代码。

使用 extension 在 类/结构体已有代码外,但在同一个文件内。

请注意 extension 内的代码不能被子类重写,这也意味着测试很难进行。 如果这是经常发生的情况,为了代码一致性最好统一使用第一种办法。否则使用第二种办法,其可以代码分割更清晰。

使用而第二种方法的时候,使用  // MARK:  依然可以让代码在 Xcode 可读性更强。

3.7 属性

3.7.1 对于只读属性,计算后(Computed)属性, 提供 getter 而不是 get {}。

1
2
3
4
5
6
var  computedProperty: String {
     if  someBool {
         return  "I'm a mighty pirate!"
     }
     return  "I'm selling these fine leather jackets."
}

3.7.2 对于属性相关方法 get {}, set {}, willSet, 和 didSet, 确保缩进相关代码块。

3.7.3 对于willSet/didSet 和 set 中的旧值和新值虽然可以自定义名称,但推荐使用默认标准名称 newValue/oldValue。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var  computedProperty: String {
     get {
         if  someBool {
             return  "I'm a mighty pirate!"
         }
         return  "I'm selling these fine leather jackets."
     }
     set {
         computedProperty = newValue
     }
     willSet {
         print( "will set to \(newValue)" )
     }
     didSet {
         print( "did set from \(oldValue) to \(newValue)" )
     }
}

3.7.4 在创建类常量的时候,使用 static 关键词修饰。

1
2
3
4
class MyTableViewCell: UITableViewCell {
     static let kReuseIdentifier = String(MyTableViewCell)
     static let kCellHeight: CGFloat = 80.0
}

3.7.5 声明单例属性可以通过下面方式进行:

1
2
3
4
class PirateManager {
     static let sharedInstance = PirateManager()
     /* ... */
}

3.8 闭包

3.8.1 如果参数的类型很明显,可以在函数名里可以省略参数类型, 但明确声明类型也是允许的。 代码的可读性有时候是添加详细的信息,而有时候部分重复,根据你的判断力做出选择吧,但前后要保持一致性。

1
2
3
4
5
6
7
8
9
10
// 省略类型
doSomethingWithClosure() { response  in
     print(response)
}
// 明确指出类型
doSomethingWithClosure() { response: NSURLResponse  in
     print(response)
}
// map 语句使用简写
[1, 2, 3].flatMap { String($0) }

3.8.2 如果使用捕捉列表 或 有具体的非 Void返回类型,参数列表应该在小括号内, 否则小括号可以省略。

1
2
3
4
5
6
7
8
// 因为使用捕捉列表,小括号不能省略。
doSomethingWithClosure() { [weak self] (response: NSURLResponse)  in
     self?.handleResponse(response)
}
// 因为返回类型,小括号不能省略。
doSomethingWithClosure() { (response: NSURLResponse) -> String  in
     return  String(response)
}

3.8.3 如果闭包是变量类型,不需把变量值放在括号中,除非需要,如变量类型是可选类型(Optional?), 或当前闭包在另一个闭包内。确保闭包里的所以参数放在小括号中,这样()表示没有参数,Void 表示不需要返回值。

1
2
3
4
5
6
7
let completionBlock: (success: Bool) -> Void = {
     print( "Success? \(success)" )
}
let completionBlock: () -> Void = {
     print( "Completed!" )
}
let completionBlock: (() -> Void)? = nil

3.9 数组

3.9.1 基本上不要通过下标直接访问数组内容,如果可能使用如 .first 或 .last, 因为这些方法是非强制类型并不会崩溃。 推荐尽可能使用 for item in items 而不是 for i in 0..<items.count 遍历数组。="" 如果需要通过下标访问数组内容,在使用前要做边界检查。<="" p="">

3.9.2 不要使用 += 或 + 操作符给数组添加新元素,使用性能较好的.append() 或.appendContentsOf()  ,如果需要声明数组基于其他的数组并保持不可变类型, 使用 let myNewArray = [arr1, arr2].flatten(),而不是let myNewArray = arr1 + arr2 。

3.10 错误处理

假设一个函数 myFunction 返回类型声明为 String,但是总有可能函数会遇到error,有一种解决方案是返回类型声明为 String?, 当遇到错误的时候返回 nil。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func readFile(withFilename filename: String) -> String? {
     guard let file = openFile(filename)  else  {
         return  nil
     }
     let fileContents = file.read()
     file.close()
     return  fileContents
}
func printSomeFile() {
     let filename =  "somefile.txt"
     guard let fileContents = readFile(filename)  else  {
         print( "不能打开 \(filename)." )
         return
     }
     print(fileContents)
}

实际上如果预知失败的原因,我们应该使用Swift 中的 try/catch 。

定义 错误对象 结构体如下:

1
2
3
4
5
6
7
8
9
10
11
12
struct Error: ErrorType {
     public let file: StaticString
     public let  function : StaticString
     public let line: UInt
     public let message: String
     public init(message: String, file: StaticString =  #file, function: StaticString = #function, line: UInt = #line) {
         self.file = file
         self. function  =  function
         self.line = line
         self.message = message
     }
}

使用案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func readFile(withFilename filename: String) throws -> String {
     guard let file = openFile(filename)  else  {
         throw  Error(message: “打不开的文件名称 \(filename).")
     }
     let fileContents = file.read()
     file.close()
     return  fileContents
}
func printSomeFile() {
     do  {
         let fileContents =  try  readFile(filename)
         print(fileContents)
     }  catch  {
         print(error)
     }
}

其实项目中还是有一些场景更适合声明为可选类型,而不是错误捕捉和处理,比如在获取远端数据过程中遇到错误,nil作为返回结果是合理的,也就是声明返回可选类型比错误处理更合理。

整体上说,如果一个方法有可能失败,并且使用可选类型作为返回类型会导致错误原因湮没,不妨考虑抛出错误而不是吃掉它。

3.11 使用 guard 语句

3.11.1 总体上,我们推荐使用提前返回的策略,而不是 if 语句的嵌套。使用 guard 语句可以改善代码的可读性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 推荐
func eatDoughnut(atIndex index: Int) {
     guard index >= 0 && index < doughnuts  else  {
         // 如果 index 超出允许范围,提前返回。
         return
     }
     let doughnut = doughnuts[index]
     eat(doughnut)
}
// 不推荐
func eatDoughnuts(atIndex index: Int) {
     if  index >= 0 && index < donuts.count {
         let doughnut = doughnuts[index]
         eat(doughnut)
     }
}

3.11.2 在解析可选类型时,推荐使用 guard 语句,而不是 if 语句,因为 guard 语句可以减少不必要的嵌套缩进。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 推荐
guard let monkeyIsland = monkeyIsland  else  {
     return
}
bookVacation(onIsland: monkeyIsland)
bragAboutVacation(onIsland: monkeyIsland)
// 不推荐
if  let monkeyIsland = monkeyIsland {
     bookVacation(onIsland: monkeyIsland)
     bragAboutVacation(onIsland: monkeyIsland)
}
// 禁止
if  monkeyIsland == nil {
     return
}
bookVacation(onIsland: monkeyIsland!)
bragAboutVacation(onIsland: monkeyIsland!)

3.11.3 当解析可选类型需要决定在 if 语句 和 guard 语句之间做选择时,最重要的判断标准是是否让代码可读性更强,实际项目中会面临更多的情景,如依赖 2 个不同的布尔值,复杂的逻辑语句会涉及多次比较等,大体上说,根据你的判断力让代码保持一致性和更强可读性, 如果你不确定 if 语句 和 guard 语句哪一个可读性更强,建议使用 guard 。

1
2
3
4
5
6
7
8
9
10
11
12
// if 语句更有可读性
if  operationFailed {
     return
}
// guard 语句这里有更好的可读性
guard isSuccessful  else  {
     return
}
// 双重否定不易被理解 - 不要这么做
guard !operationFailed  else  {
     return
}

3.11.4  如果需要在2个状态间做出选择,建议使用if 语句,而不是使用 guard 语句。

1
2
3
4
5
6
7
8
9
10
11
12
// 推荐
if  isFriendly {
     print( "你好, 远路来的朋友!" )
}  else  {
     print(“穷小子,哪儿来的?")
}
// 不推荐
guard isFriendly  else  {
     print( "穷小子,哪儿来的?" )
     return
}
print( "你好, 远路来的朋友!" )

3.11.5  你只应该在在失败情形下退出当前上下文的场景下使用 guard 语句,下面的例子可以解释 if 语句有时候比 guard 语句更合适 – 我们有两个不相关的条件,不应该相互阻塞。

1
2
3
4
5
6
if  let monkeyIsland = monkeyIsland {
     bookVacation(onIsland: monkeyIsland)
}
if  let woodchuck = woodchuck where canChuckWood(woodchuck) {
     woodchuck.chuckWood()
}

3.11.6 我们会经常遇到使用 guard 语句拆包多个可选值,如果所有拆包失败的错误处理都一致可以把拆包组合到一起 (如 return, break, continue,throw 等).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 组合在一起因为可能立即返回
guard let thingOne = thingOne,
     let thingTwo = thingTwo,
     let thingThree = thingThree  else  {
     return
}
// 使用独立的语句 因为每个场景返回不同的错误
guard let thingOne = thingOne  else  {
     throw  Error(message:  "Unwrapping thingOne failed." )
}
guard let thingTwo = thingTwo  else  {
     throw  Error(message:  "Unwrapping thingTwo failed." )
}
guard let thingThree = thingThree  else  {
     throw  Error(message:  "Unwrapping thingThree failed." )
}

4. 文档/注释

4.1 文档

如果一个函数比 O(1) 复杂度高,你需要考虑为函数添加注释,因为函数签名(方法名和参数列表) 并不是那么的一目了然,这里推荐比较流行的插件 VVDocumenter. 不论出于何种原因,如果有任何奇淫巧计不易理解的代码,都需要添加注释,对于复杂的 类/结构体/枚举/协议/属性 都需要添加注释。所有公开的 函数/类/变量/枚举/协议/属性/常数 也都需要添加文档,特别是 函数声明(包括名称和参数列表) 不是那么清晰的时候。

写文档时,确保参照苹果文档中提及的标记语法合集。

在注释文档完成后,你应检查格式是否正确。

规则:

4.1.1 一行不要超过160个字符 (和代码长度限制雷同).

4.1.2 即使文档注释只有一行,也要使用模块化格式 (/** */).

4.1.3 注释模块中的空行不要使用 * 来占位。

4.1.4 确定使用新的 – parameter 格式,而不是就得 Use the new -:param: 格式,另外注意 parameter 是小写的。

4.1.5 如果需要给一个方法的 参数/返回值/抛出异常 添加注释,务必给所有的添加注释,即使会看起来有部分重复,否则注释会看起来不完整,有时候如果只有一个参数值得添加注释,可以在方法注释里重点描述。

4.1.6 对于负责的类,在描述类的使用方法时可以添加一些合适的例子,请注意Swift注释是支持 MarkDown 语法的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
  ## 功能列表
  这个类提供下一下很赞的功能,如下:
  - 功能 1
  - 功能 2
  - 功能 3
  ## 例子
  这是一个代码块使用四个空格作为缩进的例子。
      let myAwesomeThing = MyAwesomeClass()
      myAwesomeThing.makeMoney()
  ## 警告
  使用的时候总注意以下几点
  1. 第一点
  2. 第二点
  3. 第三点
  */
class MyAwesomeClass {
     /* ... */
}

4.1.8 在写文档注释时,尽量保持简洁。

4.2 其他注释原则

4.2.1  // 后面要保留空格。

4.2.2 注释必须要另起一行。

4.2.3 使用注释 // MARK: - xoxo 时, 下面一行保留为空行。

1
2
3
4
5
6
7
8
class Pirate {
     // MARK: - 实例属性
     private let pirateName: String
     // MARK: - 初始化
     init() {
         /* ... */
     }
}

英文原文:Swift Style Guide
CocoaChina文章链接:http://www.cocoachina.com/swift/20160725/17176.html


swift/dart代码规范检查工具介绍 swift/dart代码规范检查工具介绍 简介: 本篇主要介绍swift和dart代码规范检查工具,以及他们的工作原理,操作过程,代码规范规则。 1 swift代码检查工具-swiftlint 1.1 介绍swiftlint SwiftLint 是 realm 公司开发的一个插件,专门用于管理 Swift 代码的规范。 1.2 swiftlint工作原理 SwiftLint 的工作原理是检查 Swift 代码编译过程中的 AST 和 SourceKit 环节,从而可以摆脱不同版本 Swift 语法变化的 阅读详情

相关推荐

Swift:Swift最佳实践与代码规范_2024-07-15_00-05-02.Tex

在Swift中,类和结构体是实现面向对象编程的基石。它们允许你定义自定义类型,封装数据和行为。类和结构体的定义应该清晰、简洁,并遵循Swift的命名约定。// 定义一个结构体// 定义一个类闭包是Swift中用于封装一段可以被传递和执行的代码的结构。它们可以捕获和存储上下文中的常量和变量,这使得闭包在处理异步操作和事件处理时非常有用。

907

Swift编码规范(目前swift 4.2,持续更新)

参考项目实际、官方文档、raywenderlich(传送门)等大神总结的swift语言的编码规范,适应目前swift 4.2,笔者会不定期更新,欢迎指正补充 约定,请尽量确保代码编译不残留warning,这有可以规避很多问题 目录命名规范排版格式注释函数闭包变量 命名规范 打开 -Wunguarded-availability 在调用高版本API时候报warning,为避免warning过多而忽视...

听海时节的博客 3069

从仿真到真机:如何将XTDrone的VINS-Fusion+RTABMap建图方案部署到真实无人机上?

本文详细介绍了如何将XTDrone的VINS-Fusion+RTABMap建图方案从仿真环境迁移到真实无人机上。内容涵盖硬件选型、传感器配置、VINS-Fusion调优、RTABMap性能优化以及系统集成等关键步骤,特别针对三维稠密重建在真实环境中的挑战提供了实用解决方案。

weixin_29056781的博客 241

Swift代码规范

一行不要超过160个字符 左大括号不换行 运算符( + - * / == != ->)左右加空格, let myValue = 20 + (30 / 2) * 3 逗号、冒号的后面加空格,但遇到后面是小括号则不需要加空格 func insert(_ newElement: Element, atIndex i: Int) -> Int {}let myValue = [1, 2, 3,

柳婼 の blog 1096

AXI总线的Burst Type以及地址计算 | WRAP到底是怎么一回事?

AXI总线的transaction是burst-based的,因此有必要好好研究一下不同burst type的工作原理。此处略过burst的定义以及burst size、burst length等信号的介绍。

qiuzhongyu123的博客 2万+

S7-200 SMART Modbus RTU从站配置与调试实战指南

本文提供了一份详细的S7-200 SMART PLC配置为Modbus RTU从站的实战指南。内容涵盖从硬件基础、软件准备、指令库调用、核心编程到地址映射与调试排错的完整流程。重点解析了MBUS_INIT与MBUS_SLAVE指令的关键参数配置,并深入探讨了Modbus地址与PLC内部V存储区的对应关系,帮助工程师快速打通通讯链路,实现与上位机、触摸屏等主站设备的稳定数据交互。

potato的博客 751

【swift 代码规范】

说明:一个好的团队,理所当然有其严格的代码规范,好的代码不仅可以提高团队的开放效率,也更利于团队项目的后期维护,统一的代码风格,也是团队的核心,所以规范代码很有必要!

飞落的眼泪的专栏 2254

避坑指南:PyCINRAD处理CINRAD雷达数据时遇到的5个典型报错及解决方案

本文针对使用PyCINRAD库处理CINRAD雷达基数据时常见的5个典型报错,提供了详细的解决方案。内容涵盖环境配置、数据读取、PPI可视化及性能优化等核心环节,重点解决了版本兼容性、数据异常处理和中文乱码等实际问题,帮助用户高效处理雷达基数据并生成准确的PPI图像。

cc789的博客 1067

最完整的Swift代码规范实践指南:从风格到自动化检查

Swift作为苹果生态系统的核心编程语言,其代码规范不仅影响团队协作效率,更直接关系到应用性能与可维护性。本指南将带你系统掌握Swift代码规范的核心要点,从基础命名规范到高级自动化检查工具的配置,帮助你写出清晰、一致且专业的Swift代码。无论你是刚入门的新手还是有经验的开发者,这份实践指南都能让你的代码质量提升到新高度。 ## 为什么Swift代码规范如此重要? 🚀 在团队开发中,统一的

gitblog_00468的博客 710

Vue+ECharts-GL 3D地图实战:5层叠加打造炫酷中国地图(附完整代码)

本文详细介绍了如何利用Vue和ECharts-GL构建具有强烈立体感的3D中国地图。通过5层图层的巧妙叠加与样式调校,实现了从背景阴影到交互高光的完整视觉层次,并整合了动态飞线与散点标记。文章提供了完整的代码实现、核心配置解析以及性能优化与视觉调优的实战技巧,帮助开发者快速打造专业级的交互式地图可视化应用。

d6e7f8g9h的博客 649

7.91版本unidbg调用方式

【代码】xhs最新7.91版本unidbg调用方式。

Codeooo 博客 1107

终极Swift代码规范指南:从TabView到SwiftLint的完整实践方案

Swift代码规范是每个iOS开发者必须掌握的核心技能,它能显著提升代码质量和团队协作效率。本文将为您详细介绍从基础设置到高级工具的完整Swift代码规范实践方案,帮助您构建更专业的Swift项目。 ## 🚀 为什么需要Swift代码规范? 在Swift开发中,代码规范不仅仅是个人习惯的问题,它直接关系到项目的可维护性、可读性和团队协作效率。Swift代码规范能够确保您的代码在团队中保持一致

gitblog_00486的博客 783

使用 Simulink 实现基于相控阵雷达的波束形成技术

摘要:本文详细介绍了利用MATLAB Simulink和Phased Array System工具箱实现相控阵雷达波束形成的完整流程。主要内容包括:1)创建Simulink模型;2)设计天线阵列参数;3)信号生成模块配置;4)波束形成算法实现;5)结果可视化方法;6)仿真调试与优化;7)代码导出与部署。通过分步指导,读者可以掌握从理论到实践的完整开发流程,包括关键参数设置和算法实现示例。该方案适用于军事、气象等领域的雷达系统开发,并支持后续嵌入式和智能算法集成。

xiaoheshang_123的博客 179

raywenderlich.com官方Swift代码规范指南

[TODO] 本文翻译于The Official raywenderlich.com Swift Style Guide。目前更新到 Swfit4.2。 前言:作为一名开发人员,须知好的代码规范,不仅能够提升代码的可读性、提升开发效率同时也会对让团队间的开发沟通效果得到加强。针对Swift语言raywenderlich.com给出来一份较为完善的开发指南。本文就是基于原文翻译而成。英文水平较好这...

FY_Fish的专栏 698

零基础教你学RDMA驱动开发--第8篇:队列对(QP)、完成队列(CQ)与工作请求(WR)机制剖析

本文深入剖析了RDMA(远程直接内存访问)中的核心机制:队列对(QP)、完成队列(CQ)和工作请求(WR)。QP作为通信端点包含发送队列(SQ)和接收队列(RQ);WR是用户提交的操作指令,转换为工作队列元素(WQE)后由网卡异步执行;CQ则提供完成通知机制。文章详细介绍了三者的协作原理,包括QP状态机、WR提交方式、CQ轮询机制,以及关键的信号控制技术(Signaled Mode)来优化性能。同时对比了SEND/RECV和RDMA WRITE两种模式的差异,提供了调试技巧和最佳实践。这些机制共同构成了RD

amy_mhd的博客 156

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

终极Swift代码规范指南:从基础到SiriKit集成的完整实践

Swift作为Apple生态系统的核心编程语言,其代码规范不仅影响项目的可维护性,更是团队协作效率的关键。本指南基于GitHub加速计划的swift-style-guide项目,为新手和普通用户提供从基础规范到高级集成的完整实践方案,帮助你写出清晰、一致且专业的Swift代码。 ## 为什么代码规范对Swift开发至关重要 🚀 在Swift开发中,一致的代码风格能显著降低维护成本。想象一个场

gitblog_01081的博客 820

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Penpot 设计系统配置指南:令牌、组件与原型交互实战

前端拿到设计文件,主按钮 #4A90D9、次按钮 #4A90EA,圆角有 8 有 9,间距全靠肉眼对。想改个主色,得翻遍每个图层。Penpot 的解法是把颜色、间距沉淀成设计令牌,把按钮沉淀成组件:改一处,处处生效,交付还能直接导出 JSON。 有和没有设计系统,日常差别大概是这样: | 日常工作 | 没有设计系统 | 有设计系统 | | --- | --- | --- | | 更换品牌主色

gitblog_00659的博客 868

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

最完整Swift代码规范指南:从混乱到专业的蜕变

Swift作为苹果生态系统的核心编程语言,其代码规范不仅影响开发效率,更直接关系到项目的可维护性和团队协作。本文将详细介绍Swift代码规范的核心要点,帮助开发者从混乱的代码风格转变为专业级的编码实践,同时结合工具自动化确保规范落地。 ## 为什么需要Swift代码规范? 在多人协作的项目中,统一的代码风格能显著降低沟通成本。研究表明,开发者80%的时间用于阅读代码,仅20%用于编写。一个清晰

gitblog_00293的博客 355

终极Swift代码规范指南:提升iOS开发效率的完整实践

Swift作为iOS和macOS开发的首选语言,其代码规范对于项目的可维护性和团队协作至关重要。本文将深入解析gh_mirrors/swi/swift-style-guide项目中的最佳实践,帮助开发者编写清晰、一致且高效的Swift代码。通过遵循这些经过验证的规范,你可以显著提升代码质量并减少团队协作中的摩擦。 ## 为什么代码规范对Swift开发至关重要 🚀 在现代iOS开发中,代码规范

gitblog_00188的博客 968

终极SwiftLint配置指南:10分钟实现Swift代码规范自动化检查

想要告别混乱的Swift代码,让团队协作更加顺畅吗?SwiftLint作为Swift代码规范检查的终极工具,能够帮助您快速实现代码风格的统一管理。本指南将详细介绍如何使用SwiftLint配置文件来实现高效的Swift代码规范检查。 SwiftLint是一个强大的Swift代码规范检查工具,能够自动检测代码中的不规范写法,确保项目代码风格的一致性。通过简单的配置,您就能享受到专业的代码审查体验。

gitblog_00144的博客 980
上一篇: iOS TableView给力动画的简单实现
下一篇: 唐巧总结的40个国人iOS技术博客
TY_IOS
博客等级 码龄11年 16粉丝 34原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值