preface

This document is to translate the famous Raywenderlich Swift Style Guide and generate the original address in combination with its own situation

Table of contents

  • The basic principles
  • Names * constants and variables * enumerations * class prefixes * generics * Use International English instead of American English
  • Code structure * protocol * useless code
  • The blank space
  • annotation
  • Class declaration annotation
  • Description and references to methods
  • Classes and Structs * When to use Class and when to use Struct? * Computed properties * Final
  • closure
  • Type * constant * Type inference * Optional type * initialization struct * lazy loading * syntactic sugar
  • Memory management
  • Process control
  • The control flow
  • Golden Path
  • A semicolon
  • parentheses

The basic principles

Treat warnings as errors (a robust project should have no warnings)

named

Use camelback nomenclature for classes, methods, variables, etc. Class and protocol names should be capitalized, while method and variable names should start with lower case. Constants should begin with k

Recommendation:

private let kMaximumWidgetCount = 100

class WidgetContainer {
  var widgetButton: UIButton
  let widgetHeightPercentage = 0.85
}
Copy the code

Is not recommended:

let MAX_WIDGET_COUNT = 100

class app_widgetContainer {
  var wBut: UIButton
  let wHeightPct = 0.85
}
Copy the code

Abbreviations and acronyms should generally be avoided and should be capitalized or lowercase. Example:

recommended

let urlString: URLString
let userID: UserID
Copy the code

Is not recommended

let uRLString: UrlString
let userId: UserId
Copy the code

For functions and init methods, you tend to name all parameters unless the context is very clean and clear. We can also include external parameter names if it makes the function more readable.

func dateFromString(dateString: String) -> NSDate
func convertPointAt(column column: Int, row: Int) -> CGPoint
func timedAction(afterDelay delay: NSTimeInterval, perform action: SKAction) -> SKAction!

// Call method:
dateFromString("2014-03-14")
convertPointAt(column: 42, row: 13)
timedAction(afterDelay: 1.0, perform: someOtherAction)
Copy the code

Constants and variables

1. Public variables: use the Public modifier. If the variable is mandatory, use it! If it is an optional argument, use? Mark 2. Private variables: use private.

The enumeration

According to the Swift3 apple code specification, enumeration names should begin with a capital letter and enumeration values use small humps. Such as:

enum Shape {
  case rectangle
  case square
  case rightTriangle
  case equilateralTriangle
}
Copy the code

OC naming uses the capital camel case nomenclature, and enumeration values must start with an enumeration name for easy mixing with Swift

typedef NS_ENUM(NSUInteger, OKIShape) {
  case OKIShareRectangle
  case OKIShareSquare
  case OKIShareTriangle
  case OKIShareCircle
}
Copy the code

Class prefix

Swift should not have a class prefix, but in keeping with the OC specification, the project class prefix is OK + the first letter of the project name

The generic

Generic type parameters should have descriptive, capital camel – shaped names. For type names that do not have a meaningful relationship or role, use traditional single uppercase letters, such as T, U, or V

Recommendation:

struct Stack<Element> {... }func writeTo<Target: OutputStream>(inout target: Target)
func max<T: Comparable>(x: T, _ y: T) -> T
Copy the code

Is not recommended:

struct Stack<T> {... }func writeTo<target: OutputStream>(inout t: target)
func max<Thing: Comparable>(x: Thing, _ y: Thing) -> Thing
Copy the code

Use international English instead of American English

Recommendation:

let color = "red"
Copy the code

Is not recommended:

let colour = "red"
Copy the code

The code structure

Use extensions to organize code into blocks of logical functionality. Each extension should be set with a comment :// MARK: – Keep good comments.

Protocol consistency

In Swift, it is recommended to use extension to divide the code, which can better enhance the user’s reading experience visually. Of course, don’t forget to add //MARK: –

Recommendation:

class MyViewcontroller: UIViewController {
  // class stuff here
}

// MARK: - If this extension needs to be explained, it can be commented here
extension MyViewcontroller: UITableViewDataSource {
  // table view data source methods
}

// MARK: - UIScrollViewDelegate
extension MyViewcontroller: UIScrollViewDelegate {
  // scroll view delegate methods
}
Copy the code

Is not recommended:

class MyViewcontroller: UIViewController.UITableViewDataSource.UIScrollViewDelegate {
  // all methods
}
Copy the code

Dead code

Remove unnecessary code and comments from files to keep the interface clean

Is not recommended:

override func didReceiveMemoryWarning(a) {
   super.didReceiveMemoryWarning()
  // Dispose of any resources that can be recreated.
}

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
   // #warning Incomplete implementation, return the number of sections
   return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  // #warning Incomplete implementation, return the number of rows
  return Database.contacts.count
}

Copy the code

Recommendation:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  return Database.contacts.count
}
Copy the code

The blank space

  • Use Spaces instead of tabs, and always use 4 Spaces for line breaks instead of tabs.
  • You can set your IDE to automatically convert input tabs to Spaces.
if user.isHappy
{
  // Do something
}
else {
  // Do something else
}
Copy the code
  • Methods should have a blank line between them to help in visual clarity and organization. Empty lines within a method should separate individual functions, but having too many separate groups in a method usually means you should refactor the method.

  • There is no space to the left of the colon and a space to the right. But the trinary operator (? 🙂 and empty dictionary ([:]) exceptions

Recommendation:

class TestDatabase: Database {
  var data: [String: CGFloat] = ["A": 1.2."B": 3.2]}Copy the code

Is not recommended:

class TestDatabase : Database {
  var data :[String:CGFloat] = ["A" : 1.2."B":3.2]}Copy the code

The length of each line should not exceed 120

If the length of each line is too long, it will affect the reading experience of the code. For example, some developers prefer to open the left and right pannel at the same time. Then 120 characters per line is the best length to ensure that the IDE does not break lines when switching the pannel left and right. You can set the maximum length of each warning line in Xcode (Preferences > Text Editing > Page Guide at Column: 120)

Do not use C’s parenthesis forms of Spaces and newlines

Conditional control statements, such as if/else/while/switch, should have the opening parenthesis on the line and the closing parenthesis on the new line.

Recommendation:

if user.isHappy {
  // Do something
} else {
  // Do something else
}
Copy the code

Is not recommended:

if user.isHappy
{
    // Do something
}
else {
    // Do something else
}
Copy the code

If the method name is too long and needs a line break, leave 4 Spaces on the second line

When a function exceeds 120, line breaks can be started in appropriate places (such as the end of an argument).

Recommendation:

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

annotation

First, while annotations are important, the best kind of annotation is self-documenting. Comments are used to explain what a particular piece of code does or why it does it. Also, comments must be able to remain updated or deleted. Exception: This does not apply to comments that are used to generate documentation.

Class declaration annotation

Each class, category, or Protocol requires an annotation explaining what it does and how to use it. Comments should include an overview, required parameters, version information, author, update information, such as:

/// describes the function of this class and how to use the /// /// parameter: necessary parameter /// /// @since version information /// @author Update author update informationCopy the code

In addition, if the method is public, comment each method, including parameters, return values, and notice conditions

Comments in the implementation

Use vertical lines instead of quotation marks to eliminate ambiguity, such as:

// Sometimes we need `count` to be less than zero. Or the case with quotation marks, as in:

// Remember to call `StringWithoutSpaces(“foo bar baz”)`

Do not embed snippets in comments

Do not embed code snippets in comments, as the code should be as self-documenting as possible and is not conducive to automatic documentation

Description and references to methods

When referring to methods and including the required parameter names, they should be named from the caller’s point of view, or use _ as the default.

Call convertPointAt(column:row:) from your init method call. If you call dateFromString(_:) make sure you provide a format for"yyyy-MM-dd"If you call the method timedAction(afterDelay: Perform :) from viewDidLoad(), remember to provide an adjustment delay value and an action to perform the method. You should not call the data source method directly: tableView(_:cellForRowAtIndexPath:).Copy the code

If in doubt, follow Xcode’s approach in the jump bar and keep the style consistent.

Classes and structures

When to use Class and when to use Struct?

In Swift, Class is a reference type and Struct is a value type. Value types have many advantages. For example, when you pass a value type to another object, it is a deep copy operation. Said although someone might value type is relatively time consuming (indeed, relative to a reference type, transfer value type is a little bit time consuming), however, we should think in today’s world, this is not the complexity level of the time-consuming (take a constant) as compared to the benefits of value types can be very obvious, Therefore, we recommend that you give priority to the use of Value types in Swift. Don’t worry about performance issues until you really see them.) Here’s a brief description of the Class used when creating objects:

1. Select Class when an object is unique: If you want to create an object with identifer, such as User, Task, even if two users have the same name but different Uids indicate that they are not the same person, then Class is more appropriate. But for example the user. Birthday might be a Date(your own Date), which is a better Struct because both users are equal on October 1 if they were both born on October 1.

2. Don’t fight the system API: If the system API tells you to pass a Class, pass a Class. Don’t try to fight the system (especially using dark magic that only you can understand).

Do not use self explicitly unless the syntax requires it

In Swift, the default call to a method or property does not require self. XXX. In addition, Swift requires Closure to use self. XXX to explicitly indicate that self has been retained. In normal method calls and property calls, do not use self. XXX to avoid ambiguity.

class BoardLocation {
  let row: Int, column: Int

  init(row: Int, column: Int) {
    self.row = row
    self.column = column
    
    let closure = {
      print(self.row)
    }
  }
}
Copy the code

Computed Property

If a Computed Property is read-only, do not write get:

Recommendation:

var diameter: Double {
  return radius * 2
}
Copy the code

Is not recommended:

var diameter: Double {
  get {
    return radius * 2}}Copy the code

Final

When a custom class is not allowed to be inherited, the class should be marked with final. Such as:

The Box class is not allowed to be inherited
final class Box<T> {
  let value: T 
  init(_ value: T) {
    self.value = value
  }
}
Copy the code

Closure (Closures)

Use trailing closure syntax whenever possible. In all cases, closure parameters need to have a descriptive name.

Keep an eye out for circular references in closures and use [weak self] to solve this problem

Recommendation:

UIView.animateWithDuration(1.0) {
  self.myView.alpha = 0
}

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

Is not recommended:

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

UIView.animateWithDuration(1.0,
  animations: {
    self.myView.alpha = 0
  }) { f in
    self.myView.removeFromSuperview()
}
Copy the code

Closures with one-line expressions can be returned implicitly if the context is clear

attendeeList.sort { a, b in
  a > b
}
Copy the code

Type (Types)

Try to use Swift’s native type, which Swift can call OC through a bridge file. When you declare an attribute, you tend to declare the type of the attribute as well.

Recommendation:

let width = 120.0                                    // Double
let widthString = (width as NSNumber).stringValue    // String
Copy the code

Is not recommended:

let width: NSNumber = 120.0                          // NSNumber
let widthString: NSString = width.stringValue        // NSString
Copy the code

In Sprite Kit code, use CGFloat if it makes the code cleaner and avoids too many conversions

Constants (Constants)

Use let to define constants and var to define variables. If a variable does not change, use let instead of var. You should always use let instead of var for classes, because classes are reference types, and var and let modifiers do not prevent their properties from being modified

Tip: A good technique is to define all properties with let and only change to var when prompted by the compiler.

Type Inference

Although type inference by the compiler makes your code more compact, it means that your variable declarations are required to be more readable than before. So try to give constant or variable declarations an exact type.

Recommendation:

let maximumWidth: CGFloat = 106.5
Copy the code

Is not recommended:

let maximumWidth = 106.5
Copy the code

Optional types (Optionals)

  • Pass a variable with the type of the return value of a function if nil is possible, okay? Defined as Optional.
  • Pass! Only if you are sure that the instance variable will be used after initialization. Implicitly Unwrapped Types
  • Let’s say the subview that’s going to be created in viewDidLoad. When accessing an Optional value, use the chained Optional syntax if the value is accessed only once, or if multiple Optional values need to be accessed consecutively:
self.textContainer? .textLabel? .setNeedsDisplay()Copy the code

If let determines the optional type once and can do multiple operations in scope

if let textContainer = self.textContainer {
  // do many things with textContainer
}
Copy the code
  • When naming optional variables or attributes, avoid names such as optionalString or maybeView, because their optionality is already specified in the type declaration.
  • The if let statement tries to make the variable names consistent before and after unpacking.

Recommendation:

var subview: UIView?
var volume: Double?

// later on...
if let subview = subview, volume = volume {
  // do something with unwrapped subview and volume
}
Copy the code

Is not recommended:

var optionalSubview: UIView?
var volume: Double?

if let unwrappedSubview = optionalSubview {
  if let realVolume = volume {
    // do something with unwrappedSubview and realVolume}}Copy the code
  • Do not use strong conversions (!) Most crash errors are caused by converting a Nullable object to a nonnull object

  • We prefer guard lets to if lets because the Guard syntax forces you to implement else logic, making the wrong handle more elegant

Struct Initializers

Try to use the new Swift API instead of the Objective-C post-bridge API:

Recommendation:

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

Is not recommended:

let bounds = CGRectMake(40.20.120.80)
let centerPoint = CGPointMake(96.42)
Copy the code

It is recommended to use the Swift Constant: module. Constant instead of the C Constant: ModuleConstant:

Recommendation:

CGRect.infinite, CGRect.null
Copy the code

Is not recommended:

CGRectInfinite.CGRectNull
Copy the code

Lazy Initialization

Fine control of the lifetime of an object using delayed initialization. View controller for lazy-loaded views

style1.
private lazy var locationManager: CLLocationManager = CLLocationManager()

style2.
private lazy var locationManager: CLLocationManager = {
 let locationManager = CLLocationManager(a)return locationManager
}()

style3.
lazy var locationManager: CLLocationManager = self.makeLocationManager()

private func makeLocationManager(a) -> CLLocationManager {
  let manager = CLLocationManager()
  manager.desiredAccuracy = kCLLocationAccuracyBest
  manager.delegate = self
  manager.requestAlwaysAuthorization()
  return manager
}
Copy the code

Type Annotation for Empty Arrays and Dictionaries

Empty arrays and dictionaries, annotated with type. Use type annotation for the specified array or dictionary, multiline text.

Recommendation:

var names: [String] = []
var lookup: [String: Int] = [:]
Copy the code

Is not recommended:

var names = [String] ()var lookup = [String: Int] ()Copy the code

Syntactic Sugar

Use types to define a shortcut syntax rather than a full syntax

Recommendation:

var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?
Copy the code

Is not recommended:

var deviceModels: Array<String>
var employees: Dictionary<Int.String>
var faxNumber: Optional<Int>
Copy the code

Memory Management

Recommendation:

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

Is not recommended:

// If self is released before response is returned, a crash may occur
resource.request().onComplete { [unowned self] response in
  let model = self.updateModel(response)
  self.updateUI(model)
}
Copy the code

Is not recommended:

resource.request().onComplete { [weak self] response in
  let model = self? .updateModel(response)self? .updateUI(model) }Copy the code

Access Control

Control Flow

For traversal, use the for-IN format instead of the C-style for-condition-increment format

Recommendation:

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() {
  print(index)
}
Copy the code

Is not recommended:

var i = 0
while i < 3 {
  print("Hello three times")
  i += 1
}

var i = 0
while i < attendeeList.count {
  let person = attendeeList[i]
  print("\(person) is at position #\(i)")
  i += 1
}
Copy the code

Golden Path

Use guard lets instead of nested IF lets to make multiple conditional judgments

Recommendation:

func computeFFT(context: Context? , inputData: InputData?) throws -> Frequencies {

  guard let context = context else { throw FFTError.noContext }
  guard let inputData = inputData else { throw FFTError.noInputData }
    
  // use context and input to compute the frequencies
    
  return frequencies
}
Copy the code

Is not recommended:

func computeFFT(context: Context? , inputData: InputData?) throws -> Frequencies {

  if let context = context {
    if let inputData = inputData {
      // use context and input to compute the frequencies

      return frequencies
    }
    else {
      throw FFTError.noInputData
    }
  }
  else {
    throw FFTError.noContext
  }
}
Copy the code

When multiple optional types need to be unpacked. Guard lets should be used to reduce nesting. Such as:

Recommendation:

guard let number1 = number1, number2 = number2, number3 = number3 else { fatalError("impossible")}// do something with numbers
Copy the code

Is not recommended:

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")}Copy the code

A semicolon (Semicolons)

  • Swift does not require a semicolon after any statement. Semicolons are only useful if you write multiple statements on a single line.
  • The only exception to this rule is the for statement, which requires a semicolon. However, use optional for-in statements whenever possible

Recommendation:

let swift = "not a scripting language"
Copy the code

Is not recommended:

let swift = "not a scripting language";
Copy the code

# #Parentheses (Parentheses)

The parenthesis condition is not needed and should be removed.

Recommendation:

if name == "Hello" {
  print("World")}Copy the code

Is not recommended:

if (name == "Hello") {
  print("World")}Copy the code

conclusion

No rules, no fangyuan, I hope this article can help you. I will update from time to time, if there is any objection, please issue me.